diff -Nru a/Documentation/Changes b/Documentation/Changes --- a/Documentation/Changes Tue Oct 15 20:29:21 2002 +++ b/Documentation/Changes Tue Oct 15 20:29:21 2002 @@ -95,7 +95,7 @@ Make ---- -You will need Gnu make 3.77 or later to build the kernel. +You will need Gnu make 3.78 or later to build the kernel. Binutils -------- @@ -287,9 +287,9 @@ ---------- o -Make 3.77 +Make 3.78 --------- -o +o Binutils -------- diff -Nru a/Documentation/DocBook/scsidrivers.tmpl b/Documentation/DocBook/scsidrivers.tmpl --- a/Documentation/DocBook/scsidrivers.tmpl Tue Oct 15 20:29:10 2002 +++ b/Documentation/DocBook/scsidrivers.tmpl Tue Oct 15 20:29:10 2002 @@ -60,7 +60,7 @@ - + Driver structure Traditionally a lower level driver for the scsi subsystem has been diff -Nru a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches --- a/Documentation/SubmittingPatches Tue Oct 15 20:29:11 2002 +++ b/Documentation/SubmittingPatches Tue Oct 15 20:29:11 2002 @@ -243,7 +243,7 @@ if (!dev) return -ENODEV; #ifdef CONFIG_NET_FUNKINESS - init_funky_net(dev); + init_funky_net(dev); #endif Cleaned-up example: diff -Nru a/Documentation/arm/XScale/ADIFCC/80200EVB b/Documentation/arm/XScale/ADIFCC/80200EVB --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/ADIFCC/80200EVB Tue Oct 15 20:29:25 2002 @@ -0,0 +1,111 @@ + +Board Overview +----------------------------- + +This is an beta release of the Xscale Linux port to the ADI 80200EVB +evaluation board. + +The 80200EVB is an evaluation platform for ADI Engineering's high-performance +80200FCC chipset for the Intel 80200 XScale CPU. The 80200FCC is an open +source FPGA based system that contains a PCI unit and a high performance +memory controller. + +In addition to the 80200FCC, the board also contains a 16C550 UART, and 4MB +of flash. + +The board is still under development and currently only the UART is functional +as the PCI bits have not been programmed into the FPGA. + +For more information on the board, see http://www.adiengineering.com + +Port Status +----------------------------- + +Supported: + +- Onboard UART (Polled operation only) +- Cache/TLB locking on 80200 CPU + +TODO: + +- PCI when hardware supports it + +Building the Kernel +----------------------------- +change Linux makefile +make adi_evb_config +make oldconfig +make dep +make zImage + +Loading Linux +----------------------------- + +Before you can use Linux on the ADI board, you need to grab the following: + +ADI 80200EVB Monitor: + ftp://source.mvista.com/pub/xscale/ADI_EVB/monitor.srec + +ADI JFFS2 Image: + ftp://source.mvista.com/pub/xscale/ADI_EVB/adi.jffs2 + +Once you've got the Cygnus prompt, type in the following command: + + load + +On another terminal window: + + cat monitor.srec > /dev/ttyS0 + +(replace ttyS0 with the serial port you are using) + +Once completed, just type 'go' at the cygmon prompt and you should see: + + MontaVista IQ80310 Monitor Version 0.1 + monitor> + +Type 'b 115200' at the prompt and change your terminal speed to 115200 + +The first thing to do is to upload and burn the jffs2 filesystem image +onto the boards 4MB of flash: + + monitor> u c1000000 + Uploading file at 0xc1000000 + Now send file with ymodem + +Do as the monitor says and transfer the file adi.jffs2. Once complete, +the following will copy the jffs2 image to location 0x80000 in the flash. + + monitor> f 8000 c1000000 200000 + Erasing sector 0x00080000 + Writing sector 0x00080000 with data at 0xC1000000 + Erasing sector 0x000A0000 + Writing sector 0x000A0000 with data at 0xC1020000 + Erasing sector 0x000C0000 + ... + +Now use the same command as above to upload your zImage to location c1000000. +When you've done that, type 'j c1000000' to run Linux. Login as +root and you're all set to go. + +Misc Notes +----------------------------- + +The current version of the HW does not have an onboard timer, so the 80200 +PMU is not available for general use as it is being used for a timer source. + +By default, the MTD driver reserves the first 512K for bootloaders and +the remaining 3.5MB for the filesystem. You can edit drivers/mtd/map/adi_evb.c +to change this as needed for your application. + +Contributors +----------------------------- + +Thanks to ADI Engineering for providing the hardware for development + +Deepak Saxena - Initial port + +----------------------------- +Enjoy. If you have any problem please contact Deepak Saxena +dsaxena@mvista.com + diff -Nru a/Documentation/arm/XScale/IOP310/IQ80310 b/Documentation/arm/XScale/IOP310/IQ80310 --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/arm/XScale/IOP310/IQ80310 Tue Oct 15 20:29:25 2002 @@ -0,0 +1,295 @@ + +Board Overview +----------------------------- + +The Cyclone IQ80310 board is an evaluation platform for Intel's 80200 Xscale +CPU and 80312 Intelligent I/O chipset (collectively called IOP310 chipset). + +The 80312 contains dual PCI hoses (called the ATUs), a PCI-to-PCI bridge, +three DMA channels (1 on secondary PCI, one on primary PCI ), I2C, I2O +messaging unit, XOR unit for RAID operations, a bus performance monitoring +unit, and a memory controller with ECC features. + +For more information on the board, see http://developer.intel.com/iio + +Port Status +----------------------------- + +Supported: + +- MTD/JFFS/JFFS2 +- NFS root +- RAMDISK root +- 2ndary PCI slots +- Onboard ethernet +- Serial ports (ttyS0/S1) +- Cache/TLB locking on 80200 CPU +- Performance monitoring unit on 80200 CPU +- 80200 Performance Monitoring Unit +- Acting as a system controller on Cyclone 80303BP PCI backplane +- DMA engines (EXPERIMENTAL) +- 80312 Bus Performance Monitor (EXPERIMENTAL) +- Application Accelerator Unit (XOR engine for RAID) (EXPERIMENTAL) +- Messaging Unit (EXPERIMENTAL) + +TODO: +- I2C + +Building the Kernel +----------------------------- +make iq80310_config +make oldconfig +make dep +make zImage + +This will build an image setup for BOOTP/NFS root support. To change this, +just run make menuconfig and disable nfs root or add a "root=" option. + +Preparing the Hardware +----------------------------- + +This document assumes you're using a Rev D or newer board running +Redboot as the bootloader. + +The as-supplied RedBoot image appears to leave the first page of RAM +in a corrupt state such that certain words in that page are unwritable +and contain random data. The value of the data, and the location within +the first page changes with each boot, but is generally in the range +0xa0000150 to 0xa0000fff. + +You can grab the source from the ECOS CVS or you can get a prebuilt image +from: + + ftp://source.mvista.com/pub/xscale/iop310/IQ80310/redboot.bin + +which is: + + # strings redboot.bin | grep bootstrap + RedBoot(tm) bootstrap and debug environment, version UNKNOWN - built 14:58:21, Aug 15 2001 + +md5sum of this version: + + bcb96edbc6f8e55b16c165930b6e4439 redboot.bin + +You have two options to program it: + +1. Using the FRU program (see the instructions in the user manual). + +2. Using a Linux host, with MTD support built into the host kernel: + - ensure that the RedBoot image is not locked (issue the following + command under the existing RedBoot image): + RedBoot> fis unlock -f 0 -l 0x40000 + - switch S3-1 and S3-2 on. + - reboot the host + - login as root + - identify the 80310 card: + # lspci + ... + 00:0c.1 Memory controller: Intel Corporation 80310 IOP [IO Processor] (rev 01) + - in this example, bus 0, slot 0c, function 1. + - insert the MTD modules, and the PCI map module: + # insmod drivers/mtd/maps/pci.o + - locate the MTD device (using the bus, slot, function) + # cat /proc/mtd + dev: size erasesize name + mtd0: 00800000 00020000 "00:0c.1" + - in this example, it is mtd device 0. Yours will be different. + Check carefully. + - program the flash + # cat redboot.bin > /dev/mtdblock0 + - check the kernel message log for errors (some cat commands don't + error on failure) + # dmesg + - switch S3-1 and S3-2 off + - reboot host + +In any case, make sure you do an 'fis init' command once you boot with the new +RedBoot image. + + + +Downloading Linux +----------------------------- + +Assuming you have your development system setup to act as a bootp/dhcp +server and running tftp: + + RedBoot> load -r -b 0xa1008000 /tftpboot/zImage.xs + Raw file loaded 0xa1008000-0xa1094bd8 + +If you're not using dhcp/tftp, you can use y-modem instead: + + RedBoot> load -r -b 0xa1008000 -m y + +Note that on Rev D. of the board, tftp does not work due to intermittent +interrupt issues, so you need to download using ymodem. + +Once the download is completed: + + RedBoot> go 0xa1008000 + +Root Devices +----------------------------- + +A kernel is not useful without a root filesystem, and you have several +choices with this board: NFS root, RAMDISK, or JFFS/JFFS2. For development +purposes, it is suggested that you use NFS root for easy access to various +tools. Once you're ready to deploy, probably want to utilize JFFS/JFFS2 on +the flash device. + +MTD on the IQ80310 +----------------------------- + +Linux on the IQ80310 supports RedBoot FIS paritioning if it is enabled. +Out of the box, once you've done 'fis init' on RedBoot, you will get +the following partitioning scheme: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 0075f000 00020000 "unallocated space" + mtd3: 00001000 00020000 "RedBoot config" + mtd4: 00020000 00020000 "FIS directory" + +To create an FIS directory, you need to use the fis command in RedBoot. +As an example, you can burn the kernel into the flash once it's downloaded: + + RedBoot> fis create -b 0xa1008000 -l 0x8CBAC -r 0xa1008000 -f 0x80000 kernel + ... Erase from 0x00080000-0x00120000: ..... + ... Program from 0xa1008000-0xa1094bac at 0x00080000: ..... + ... Unlock from 0x007e0000-0x00800000: . + ... Erase from 0x007e0000-0x00800000: . + ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 + kernel 0x00080000 0xA1008000 0x000A0000 0x00000000 + +This leads to the following Linux MTD setup: + + mtroot@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 006bf000 00020000 "unallocated space" + mtd4: 00001000 00020000 "RedBoot config" + mtd5: 00020000 00020000 "FIS directory" + +Note that there is not a 1:1 mapping to the number of RedBoot paritions to +MTD partitions as unused space also gets allocated into MTD partitions. + +As an aside, the -r option when creating the Kernel entry allows you to +simply do an 'fis load kernel' to copy the image from flash into memory. +You can then do an 'fis go 0xa1008000' to start Linux. + +If you choose to use static partitioning instead of the RedBoot partioning: + + /dev/mtd0 0x00000000 - 0x0007ffff: Boot Monitor (512k) + /dev/mtd1 0x00080000 - 0x0011ffff: Kernel Image (640K) + /dev/mtd2 0x00120000 - 0x0071ffff: File System (6M) + /dev/mtd3 0x00720000 - 0x00800000: RedBoot Reserved (896K) + +To use a JFFS1/2 root FS, you need to donwload the JFFS image using either +tftp or ymodem, and then copy it to flash: + + RedBoot> load -r -b 0xa1000000 /tftpboot/jffs.img + Raw file loaded 0xa1000000-0xa1600000 + RedBoot> fis create -b 0xa1000000 -l 0x600000 -f 0x120000 jffs + ... Erase from 0x00120000-0x00720000: .................................. + ... Program from 0xa1000000-0xa1600000 at 0x00120000: .................. + ...................... + ... Unlock from 0x007e0000-0x00800000: . + ... Erase from 0x007e0000-0x00800000: . + ... Program from 0xa1fdf000-0xa1fff000 at 0x007e0000: . + ... Lock from 0x007e0000-0x00800000: . + RedBoot> fis list + Name FLASH addr Mem addr Length Entry point + RedBoot 0x00000000 0x00000000 0x00040000 0x00000000 + RedBoot[backup] 0x00040000 0x00040000 0x00040000 0x00000000 + RedBoot config 0x007DF000 0x007DF000 0x00001000 0x00000000 + FIS directory 0x007E0000 0x007E0000 0x00020000 0x00000000 + kernel 0x00080000 0xA1008000 0x000A0000 0xA1008000 + jffs 0x00120000 0x00120000 0x00600000 0x00000000 + +This looks like this in Linux: + + root@192.168.0.14:~# cat /proc/mtd + dev: size erasesize name + mtd0: 00040000 00020000 "RedBoot" + mtd1: 00040000 00020000 "RedBoot[backup]" + mtd2: 000a0000 00020000 "kernel" + mtd3: 00600000 00020000 "jffs" + mtd4: 000bf000 00020000 "unallocated space" + mtd5: 00001000 00020000 "RedBoot config" + mtd6: 00020000 00020000 "FIS directory" + +You need to boot the kernel once and watch the boot messages to see how the +JFFS RedBoot partition mapped into the MTD partition scheme. + +You can grab a pre-built JFFS image to use as a root file system at: + + ftp://source.mvista.com/pub/xscale/iop310/IQ80310/jffs.img + +For detailed info on using MTD and creating a JFFS image go to: + + http://www.linux-mtd.infradead.org. + +For details on using RedBoot's FIS commands, type 'fis help' or consult +your RedBoot manual. + +Contributors +----------------------------- + +Thanks to Intel Corporation for providing the hardware. + +John Clark - Initial discovery of RedBoot issues +Dave Jiang - IRQ demux fixes, AAU, DMA, MU +Nicolas Pitre - Initial port, cleanup, debugging +Matt Porter - PCI subsystem development, debugging +Tim Sanders - Initial PCI code +Mark Salter - RedBoot fixes +Deepak Saxena - Cleanup, debug, cache lock, PMU + +----------------------------- +Enjoy. + +If you have any problems please contact Deepak Saxena + +A few notes from rmk +----------------------------- + +These are notes of my initial experience getting the IQ80310 Rev D up and +running. In total, it has taken many hours to work out what's going on... +The version of redboot used is: + + RedBoot(tm) bootstrap and debug environment, version UNKNOWN - built 14:58:21, Aug 15 2001 + + +1. I've had a corrupted download of the redboot.bin file from Montavista's + FTP site. It would be a good idea if there were md5sums, sum or gpg + signatures available to ensure the integrity of the downloaded files. + The result of this was an apparantly 100% dead card. + +2. RedBoot Intel EtherExpress Pro 100 driver seems to be very unstable - + I've had it take out the whole of a 100mbit network for several minutes. + The Hub indiates ZERO activity, despite machines attempting to communicate. + Further to this, while tftping the kernel, the transfer will stall regularly, + and might even drop the link LED. + +3. There appears to be a bug in the Intel Documentation Pack that comes with + the IQ80310 board. Serial port 1, which is the socket next to the LEDs + is address 0xfe810000, not 0xfe800000. + + Note that RedBoot uses either serial port 1 OR serial port 2, so if you + have your console connected to the wrong port, you'll see redboot messages + but not kernel boot messages. + +4. Trying to use fconfig to setup a boot script fails - it hangs when trying + to erase the flash. diff -Nru a/Documentation/filesystems/afs.txt b/Documentation/filesystems/afs.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/filesystems/afs.txt Tue Oct 15 20:29:25 2002 @@ -0,0 +1,155 @@ + kAFS: AFS FILESYSTEM + ==================== + +ABOUT +===== + +This filesystem provides a fairly simple AFS filesystem driver. It is under +development and only provides very basic facilities. It does not yet support +the following AFS features: + + (*) Write support. + (*) Communications security. + (*) Local caching. + (*) pioctl() system call. + (*) Automatic mounting of embedded mountpoints. + + +USAGE +===== + +When inserting the driver modules the root cell must be specified along with a +list of volume location server IP addresses: + + insmod rxrpc.o + insmod kafs.o rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91 + +The first module is a driver for the RxRPC remote operation protocol, and the +second is the actual filesystem driver for the AFS filesystem. + +Once the module has been loaded, more modules can be added by the following +procedure: + + echo add grand.central.org 18.7.14.88:128.2.191.224 >/proc/fs/afs/cells + +Where the parameters to the "add" command are the name of a cell and a list of +volume location servers within that cell. + +Filesystems can be mounted anywhere by commands similar to the following: + + mount -t afs "%cambridge.redhat.com:root.afs." /afs + mount -t afs "#cambridge.redhat.com:root.cell." /afs/cambridge + mount -t afs "#root.afs." /afs + mount -t afs "#root.cell." /afs/cambridge + + NB: When using this on Linux 2.4, the mount command has to be different, + since the filesystem doesn't have access to the device name argument: + + mount -t afs none /afs -ovol="#root.afs." + +Where the initial character is either a hash or a percent symbol depending on +whether you definitely want a R/W volume (hash) or whether you'd prefer a R/O +volume, but are willing to use a R/W volume instead (percent). + +The name of the volume can be suffixes with ".backup" or ".readonly" to +specify connection to only volumes of those types. + +The name of the cell is optional, and if not given during a mount, then the +named volume will be looked up in the cell specified during insmod. + +Additional cells can be added through /proc (see later section). + + +MOUNTPOINTS +=========== + +AFS has a concept of mountpoints. These are specially formatted symbolic links +(of the same form as the "device name" passed to mount). kAFS presents these +to the user as directories that have special properties: + + (*) They cannot be listed. Running a program like "ls" on them will incur an + EREMOTE error (Object is remote). + + (*) Other objects can't be looked up inside of them. This also incurs an + EREMOTE error. + + (*) They can be queried with the readlink() system call, which will return + the name of the mountpoint to which they point. The "readlink" program + will also work. + + (*) They can be mounted on (which symbolic links can't). + + +PROC FILESYSTEM +=============== + +The rxrpc module creates a number of files in various places in the /proc +filesystem: + + (*) Firstly, some information files are made available in a directory called + "/proc/net/rxrpc/". These list the extant transport endpoint, peer, + connection and call records. + + (*) Secondly, some control files are made available in a directory called + "/proc/sys/rxrpc/". Currently, all these files can be used for is to + turn on various levels of tracing. + +The AFS modules creates a "/proc/fs/afs/" directory and populates it: + + (*) A "cells" file that lists cells currently known to the afs module. + + (*) A directory per cell that contains files that list volume location + servers, volumes, and active servers known within that cell. + + +THE CELL DATABASE +================= + +The filesystem maintains an internal database of all the cells it knows and +the IP addresses of the volume location servers for those cells. The cell to +which the computer belongs is added to the database when insmod is performed +by the "rootcell=" argument. + +Further cells can be added by commands similar to the following: + + echo add CELLNAME VLADDR[:VLADDR][:VLADDR]... >/proc/fs/afs/cells + echo add grand.central.org 18.7.14.88:128.2.191.224 >/proc/fs/afs/cells + +No other cell database operations are available at this time. + + +EXAMPLES +======== + +Here's what I use to test this. Some of the names and IP addresses are local +to my internal DNS. My "root.afs" partition has a mount point within it for +some public volumes volumes. + +insmod -S /tmp/rxrpc.o +insmod -S /tmp/kafs.o rootcell=cambridge.redhat.com:172.16.18.73:172.16.18.91 + +mount -t afs \%root.afs. /afs +mount -t afs \%cambridge.redhat.com:root.cell. /afs/cambridge.redhat.com/ + +echo add grand.central.org 18.7.14.88:128.2.191.224 > /proc/fs/afs/cells +mount -t afs "#grand.central.org:root.cell." /afs/grand.central.org/ +mount -t afs "#grand.central.org:root.archive." /afs/grand.central.org/archive +mount -t afs "#grand.central.org:root.contrib." /afs/grand.central.org/contrib +mount -t afs "#grand.central.org:root.doc." /afs/grand.central.org/doc +mount -t afs "#grand.central.org:root.project." /afs/grand.central.org/project +mount -t afs "#grand.central.org:root.service." /afs/grand.central.org/service +mount -t afs "#grand.central.org:root.software." /afs/grand.central.org/software +mount -t afs "#grand.central.org:root.user." /afs/grand.central.org/user + +umount /afs/grand.central.org/user +umount /afs/grand.central.org/software +umount /afs/grand.central.org/service +umount /afs/grand.central.org/project +umount /afs/grand.central.org/doc +umount /afs/grand.central.org/contrib +umount /afs/grand.central.org/archive +umount /afs/grand.central.org +umount /afs/cambridge.redhat.com +umount /afs +rmmod kafs +rmmod rxrpc diff -Nru a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt --- a/Documentation/filesystems/proc.txt Tue Oct 15 20:29:15 2002 +++ b/Documentation/filesystems/proc.txt Tue Oct 15 20:29:15 2002 @@ -966,7 +966,7 @@ Contains, as a percentage of total system memory, the number of pages at which the pdflush background writeback daemon will start writing out dirty data. -dirty_async_ratio +dirty_ratio ----------------- Contains, as a percentage of total system memory, the number of pages at which diff -Nru a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt --- a/Documentation/filesystems/vfat.txt Tue Oct 15 20:29:17 2002 +++ b/Documentation/filesystems/vfat.txt Tue Oct 15 20:29:17 2002 @@ -8,6 +8,10 @@ VFAT MOUNT OPTIONS ---------------------------------------------------------------------- +umask=### -- The permission mask (see umask(1)) for the regulare file. + The default is the umask of current process. +dmask=### -- The permission mask for the directory. + The default is the umask of current process. codepage=### -- Sets the codepage for converting to shortname characters on FAT and VFAT filesystems. By default, codepage 437 is used. This is the default for the U.S. and some @@ -31,10 +35,6 @@ illegal on the vfat filesystem. The escape sequence that gets used is ':' and the four digits of hexadecimal unicode. -posix= -- Allow names of same letters, different case such as - 'LongFileName' and 'longfilename' to coexist. This has some - problems currently because 8.3 conflicts are not handled - correctly for POSIX filesystem compliance. nonumtail= -- When creating 8.3 aliases, normally the alias will end in '~1' or tilde followed by some number. If this option is set, then if the filename is @@ -65,10 +65,6 @@ * Need to get rid of the raw scanning stuff. Instead, always use a get next directory entry approach. The only thing left that uses raw scanning is the directory renaming code. - -* Fix the POSIX filesystem support to work in 8.3 space. This involves - renaming aliases if a conflict occurs between a new filename and - an old alias. This is quite a mess. POSSIBLE PROBLEMS diff -Nru a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt --- a/Documentation/filesystems/xfs.txt Tue Oct 15 20:29:20 2002 +++ b/Documentation/filesystems/xfs.txt Tue Oct 15 20:29:20 2002 @@ -29,12 +29,6 @@ The preferred buffered I/O size can also be altered on an individual file basis using the ioctl(2) system call. - 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. diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt Tue Oct 15 20:29:23 2002 +++ b/Documentation/kernel-parameters.txt Tue Oct 15 20:29:23 2002 @@ -23,6 +23,7 @@ HW Appropriate hardware is enabled. IA-32 IA-32 aka i386 architecture is enabled. IA-64 IA-64 architecture is enabled. + IP_PNP IP DCHP, BOOTP, or RARP is enabled. ISAPNP ISA PnP code is enabled. ISDN Appropriate ISDN support is enabled. JOY Appropriate joystick support is enabled. @@ -257,7 +258,7 @@ initrd= [BOOT] Specify the location of the initial ramdisk. - ip= [PNP] + ip= [IP_PNP] isapnp= [ISAPNP] Specify RDP, reset, pci_scan and verbosity. @@ -279,10 +280,14 @@ kbd-reset [VT] - keep_initrd [HW, ARM] + keepinitrd [HW, ARM] load_ramdisk= [RAM] List of ramdisks to load from floppy. + lockd.udpport= [NFS] + + lockd.tcpport= [NFS] + logi_busmouse= [HW, MOUSE] lp=0 [LP] Specify parallel ports to use, e.g, @@ -323,6 +328,8 @@ to off as the mainboard support is not always present. You must activate it as a boot option + mca-pentium [BUGS=IA-32] + mcd= [HW,CD] mcdx= [HW,CD] @@ -335,6 +342,11 @@ megaraid= [HW,SCSI] + mem=exactmap [KNL,BOOT,IA-32] enable setting of an exact + e820 memory map, as specified by the user. + Such mem=exactmap lines can be constructed + based on BIOS output or other requirements. + mem=nn[KMG] [KNL,BOOT] force use of a specific amount of memory; to be used when the kernel is not able to see the whole system memory or for test. @@ -390,7 +402,9 @@ nohlt [BUGS=ARM] - no-hlt [BUGS=IA-32] + no-hlt [BUGS=IA-32] Tells the kernel that the hlt + instruction doesn't work correctly and not to + use it. noht [SMP,IA-32] Disables P4 Xeon(tm) HyperThreading. @@ -536,6 +550,10 @@ ro [KNL] Mount root device read-only on boot. root= [KNL] root filesystem. + + rootflags= [KNL] set root filesystem mount option string + + rootfstype= [KNL] set root filesystem type rw [KNL] Mount root device read-write on boot. diff -Nru a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt --- a/Documentation/sysctl/vm.txt Tue Oct 15 20:29:19 2002 +++ b/Documentation/sysctl/vm.txt Tue Oct 15 20:29:19 2002 @@ -18,14 +18,14 @@ Currently, these files are in /proc/sys/vm: - overcommit_memory - page-cluster -- dirty_async_ratio +- dirty_ratio - dirty_background_ratio - dirty_expire_centisecs - dirty_writeback_centisecs ============================================================== -dirty_async_ratio, dirty_background_ratio, dirty_expire_centisecs, +dirty_ratio, dirty_background_ratio, dirty_expire_centisecs, dirty_writeback_centisecs: See Documentation/filesystems/proc.txt diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Tue Oct 15 20:29:17 2002 +++ b/MAINTAINERS Tue Oct 15 20:29:17 2002 @@ -1592,6 +1592,11 @@ M: jb@technologeek.org S: Maintained +TI PARALLEL LINK CABLE DRIVER +P: Romain Lievin +M: roms@lpg.ticalc.org +S: Maintained + TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER P: Stephane Dalton M: sdalton@videotron.ca diff -Nru a/Makefile b/Makefile --- a/Makefile Tue Oct 15 20:29:12 2002 +++ b/Makefile Tue Oct 15 20:29:12 2002 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 42 +SUBLEVEL = 43 EXTRAVERSION = # *DOCUMENTATION* diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c --- a/arch/alpha/kernel/irq.c Tue Oct 15 20:29:20 2002 +++ b/arch/alpha/kernel/irq.c Tue Oct 15 20:29:20 2002 @@ -62,13 +62,13 @@ } struct hw_interrupt_type no_irq_type = { - typename: "none", - startup: no_irq_startup, - shutdown: no_irq_enable_disable, - enable: no_irq_enable_disable, - disable: no_irq_enable_disable, - ack: no_irq_ack, - end: no_irq_enable_disable, + .typename = "none", + .startup = no_irq_startup, + .shutdown = no_irq_enable_disable, + .enable = no_irq_enable_disable, + .disable = no_irq_enable_disable, + .ack = no_irq_ack, + .end = no_irq_enable_disable, }; int diff -Nru a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c --- a/arch/alpha/kernel/irq_alpha.c Tue Oct 15 20:29:13 2002 +++ b/arch/alpha/kernel/irq_alpha.c Tue Oct 15 20:29:13 2002 @@ -213,19 +213,19 @@ static unsigned int rtc_startup(unsigned int irq) { return 0; } struct irqaction timer_irqaction = { - handler: timer_interrupt, - flags: SA_INTERRUPT, - name: "timer", + .handler = timer_interrupt, + .flags = SA_INTERRUPT, + .name = "timer", }; static struct hw_interrupt_type rtc_irq_type = { - typename: "RTC", - startup: rtc_startup, - shutdown: rtc_enable_disable, - enable: rtc_enable_disable, - disable: rtc_enable_disable, - ack: rtc_enable_disable, - end: rtc_enable_disable, + .typename = "RTC", + .startup = rtc_startup, + .shutdown = rtc_enable_disable, + .enable = rtc_enable_disable, + .disable = rtc_enable_disable, + .ack = rtc_enable_disable, + .end = rtc_enable_disable, }; void __init @@ -238,16 +238,16 @@ /* Dummy irqactions. */ struct irqaction isa_cascade_irqaction = { - handler: no_action, - name: "isa-cascade" + .handler = no_action, + .name = "isa-cascade" }; struct irqaction timer_cascade_irqaction = { - handler: no_action, - name: "timer-cascade" + .handler = no_action, + .name = "timer-cascade" }; struct irqaction halt_switch_irqaction = { - handler: no_action, - name: "halt-switch" + .handler = no_action, + .name = "halt-switch" }; diff -Nru a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c --- a/arch/alpha/kernel/irq_i8259.c Tue Oct 15 20:29:20 2002 +++ b/arch/alpha/kernel/irq_i8259.c Tue Oct 15 20:29:20 2002 @@ -85,21 +85,21 @@ } struct hw_interrupt_type i8259a_irq_type = { - typename: "XT-PIC", - startup: i8259a_startup_irq, - shutdown: i8259a_disable_irq, - enable: i8259a_enable_irq, - disable: i8259a_disable_irq, - ack: i8259a_mask_and_ack_irq, - end: i8259a_end_irq, + .typename = "XT-PIC", + .startup = i8259a_startup_irq, + .shutdown = i8259a_disable_irq, + .enable = i8259a_enable_irq, + .disable = i8259a_disable_irq, + .ack = i8259a_mask_and_ack_irq, + .end = i8259a_end_irq, }; void __init init_i8259a_irqs(void) { static struct irqaction cascade = { - handler: no_action, - name: "cascade", + .handler = no_action, + .name = "cascade", }; long i; diff -Nru a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c --- a/arch/alpha/kernel/irq_pyxis.c Tue Oct 15 20:29:23 2002 +++ b/arch/alpha/kernel/irq_pyxis.c Tue Oct 15 20:29:23 2002 @@ -71,13 +71,13 @@ } static struct hw_interrupt_type pyxis_irq_type = { - typename: "PYXIS", - startup: pyxis_startup_irq, - shutdown: pyxis_disable_irq, - enable: pyxis_enable_irq, - disable: pyxis_disable_irq, - ack: pyxis_mask_and_ack_irq, - end: pyxis_end_irq, + .typename = "PYXIS", + .startup = pyxis_startup_irq, + .shutdown = pyxis_disable_irq, + .enable = pyxis_enable_irq, + .disable = pyxis_disable_irq, + .ack = pyxis_mask_and_ack_irq, + .end = pyxis_end_irq, }; void diff -Nru a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c --- a/arch/alpha/kernel/irq_srm.c Tue Oct 15 20:29:20 2002 +++ b/arch/alpha/kernel/irq_srm.c Tue Oct 15 20:29:20 2002 @@ -49,13 +49,13 @@ /* Handle interrupts from the SRM, assuming no additional weirdness. */ static struct hw_interrupt_type srm_irq_type = { - typename: "SRM", - startup: srm_startup_irq, - shutdown: srm_disable_irq, - enable: srm_enable_irq, - disable: srm_disable_irq, - ack: srm_disable_irq, - end: srm_end_irq, + .typename = "SRM", + .startup = srm_startup_irq, + .shutdown = srm_disable_irq, + .enable = srm_enable_irq, + .disable = srm_disable_irq, + .ack = srm_disable_irq, + .end = srm_end_irq, }; void __init diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c --- a/arch/alpha/kernel/pci.c Tue Oct 15 20:29:12 2002 +++ b/arch/alpha/kernel/pci.c Tue Oct 15 20:29:12 2002 @@ -102,7 +102,7 @@ #define DMAPSZ (max_low_pfn << PAGE_SHIFT) /* memory size, not window size */ if ((__direct_map_base + DMAPSZ - 1) >= 0xfff00000UL) { __direct_map_size = 0xfff00000UL - __direct_map_base; - printk("%s: adjusting direct map size to 0x%x\n", + printk("%s: adjusting direct map size to 0x%lx\n", __FUNCTION__, __direct_map_size); } else { struct pci_controller *hose = dev->sysdata; diff -Nru a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c --- a/arch/alpha/kernel/setup.c Tue Oct 15 20:29:12 2002 +++ b/arch/alpha/kernel/setup.c Tue Oct 15 20:29:12 2002 @@ -112,12 +112,12 @@ */ struct screen_info screen_info = { - orig_x: 0, - orig_y: 25, - orig_video_cols: 80, - orig_video_lines: 25, - orig_video_isVGA: 1, - orig_video_points: 16 + .orig_x = 0, + .orig_y = 25, + .orig_video_cols = 80, + .orig_video_lines = 25, + .orig_video_isVGA = 1, + .orig_video_points = 16 }; /* @@ -452,12 +452,12 @@ } static struct console srmcons = { - name: "srm0", - write: srm_console_write, - device: srm_console_device, - setup: srm_console_setup, - flags: CON_PRINTBUFFER | CON_ENABLED, /* fake it out */ - index: -1, + .name = "srm0", + .write = srm_console_write, + .device = srm_console_device, + .setup = srm_console_setup, + .flags = CON_PRINTBUFFER | CON_ENABLED, /* fake it out */ + .index = -1, }; #else @@ -1150,10 +1150,10 @@ } struct seq_operations cpuinfo_op = { - start: c_start, - next: c_next, - stop: c_stop, - show: show_cpuinfo, + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, }; diff -Nru a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c --- a/arch/alpha/kernel/sys_alcor.c Tue Oct 15 20:29:16 2002 +++ b/arch/alpha/kernel/sys_alcor.c Tue Oct 15 20:29:16 2002 @@ -91,13 +91,13 @@ } static struct hw_interrupt_type alcor_irq_type = { - typename: "ALCOR", - startup: alcor_startup_irq, - shutdown: alcor_disable_irq, - enable: alcor_enable_irq, - disable: alcor_disable_irq, - ack: alcor_mask_and_ack_irq, - end: alcor_end_irq, + .typename = "ALCOR", + .startup = alcor_startup_irq, + .shutdown = alcor_disable_irq, + .enable = alcor_enable_irq, + .disable = alcor_disable_irq, + .ack = alcor_mask_and_ack_irq, + .end = alcor_end_irq, }; static void @@ -245,29 +245,29 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_ALCOR) struct alpha_machine_vector alcor_mv __initmv = { - vector_name: "Alcor", + .vector_name = "Alcor", DO_EV5_MMU, DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_ALCOR_MAX_DMA_ADDRESS, - min_io_address: EISA_DEFAULT_IO_BASE, - min_mem_address: CIA_DEFAULT_MEM_BASE, - - nr_irqs: 48, - device_interrupt: alcor_device_interrupt, - - init_arch: cia_init_arch, - init_irq: alcor_init_irq, - init_rtc: common_init_rtc, - init_pci: cia_init_pci, - kill_arch: alcor_kill_arch, - pci_map_irq: alcor_map_irq, - pci_swizzle: common_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_ALCOR_MAX_DMA_ADDRESS, + .min_io_address = EISA_DEFAULT_IO_BASE, + .min_mem_address = CIA_DEFAULT_MEM_BASE, + + .nr_irqs = 48, + .device_interrupt = alcor_device_interrupt, + + .init_arch = cia_init_arch, + .init_irq = alcor_init_irq, + .init_rtc = common_init_rtc, + .init_pci = cia_init_pci, + .kill_arch = alcor_kill_arch, + .pci_map_irq = alcor_map_irq, + .pci_swizzle = common_swizzle, - sys: { cia: { - gru_int_req_bits: ALCOR_GRU_INT_REQ_BITS + .sys = { .cia = { + .gru_int_req_bits = ALCOR_GRU_INT_REQ_BITS }} }; ALIAS_MV(alcor) @@ -275,29 +275,29 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XLT) struct alpha_machine_vector xlt_mv __initmv = { - vector_name: "XLT", + .vector_name = "XLT", DO_EV5_MMU, DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: EISA_DEFAULT_IO_BASE, - min_mem_address: CIA_DEFAULT_MEM_BASE, - - nr_irqs: 48, - device_interrupt: alcor_device_interrupt, - - init_arch: cia_init_arch, - init_irq: alcor_init_irq, - init_rtc: common_init_rtc, - init_pci: cia_init_pci, - kill_arch: alcor_kill_arch, - pci_map_irq: alcor_map_irq, - pci_swizzle: common_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = EISA_DEFAULT_IO_BASE, + .min_mem_address = CIA_DEFAULT_MEM_BASE, + + .nr_irqs = 48, + .device_interrupt = alcor_device_interrupt, + + .init_arch = cia_init_arch, + .init_irq = alcor_init_irq, + .init_rtc = common_init_rtc, + .init_pci = cia_init_pci, + .kill_arch = alcor_kill_arch, + .pci_map_irq = alcor_map_irq, + .pci_swizzle = common_swizzle, - sys: { cia: { - gru_int_req_bits: XLT_GRU_INT_REQ_BITS + .sys = { .cia = { + .gru_int_req_bits = XLT_GRU_INT_REQ_BITS }} }; ALIAS_MV(xlt) diff -Nru a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c --- a/arch/alpha/kernel/sys_cabriolet.c Tue Oct 15 20:29:15 2002 +++ b/arch/alpha/kernel/sys_cabriolet.c Tue Oct 15 20:29:15 2002 @@ -73,13 +73,13 @@ } static struct hw_interrupt_type cabriolet_irq_type = { - typename: "CABRIOLET", - startup: cabriolet_startup_irq, - shutdown: cabriolet_disable_irq, - enable: cabriolet_enable_irq, - disable: cabriolet_disable_irq, - ack: cabriolet_disable_irq, - end: cabriolet_end_irq, + .typename = "CABRIOLET", + .startup = cabriolet_startup_irq, + .shutdown = cabriolet_disable_irq, + .enable = cabriolet_enable_irq, + .disable = cabriolet_disable_irq, + .ack = cabriolet_disable_irq, + .end = cabriolet_end_irq, }; static void @@ -321,26 +321,26 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET) struct alpha_machine_vector cabriolet_mv __initmv = { - vector_name: "Cabriolet", + .vector_name = "Cabriolet", DO_EV4_MMU, DO_DEFAULT_RTC, DO_APECS_IO, DO_APECS_BUS, - machine_check: apecs_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 35, - device_interrupt: cabriolet_device_interrupt, - - init_arch: apecs_init_arch, - init_irq: cabriolet_init_irq, - init_rtc: common_init_rtc, - init_pci: cabriolet_init_pci, - kill_arch: NULL, - pci_map_irq: cabriolet_map_irq, - pci_swizzle: common_swizzle, + .machine_check = apecs_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 35, + .device_interrupt = cabriolet_device_interrupt, + + .init_arch = apecs_init_arch, + .init_irq = cabriolet_init_irq, + .init_rtc = common_init_rtc, + .init_pci = cabriolet_init_pci, + .kill_arch = NULL, + .pci_map_irq = cabriolet_map_irq, + .pci_swizzle = common_swizzle, }; #ifndef CONFIG_ALPHA_EB64P ALIAS_MV(cabriolet) @@ -349,101 +349,101 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164) struct alpha_machine_vector eb164_mv __initmv = { - vector_name: "EB164", + .vector_name = "EB164", DO_EV5_MMU, DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: CIA_DEFAULT_MEM_BASE, - - nr_irqs: 35, - device_interrupt: cabriolet_device_interrupt, - - init_arch: cia_init_arch, - init_irq: cabriolet_init_irq, - init_rtc: common_init_rtc, - init_pci: cia_cab_init_pci, - pci_map_irq: cabriolet_map_irq, - pci_swizzle: common_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = CIA_DEFAULT_MEM_BASE, + + .nr_irqs = 35, + .device_interrupt = cabriolet_device_interrupt, + + .init_arch = cia_init_arch, + .init_irq = cabriolet_init_irq, + .init_rtc = common_init_rtc, + .init_pci = cia_cab_init_pci, + .pci_map_irq = cabriolet_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(eb164) #endif #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P) struct alpha_machine_vector eb66p_mv __initmv = { - vector_name: "EB66+", + .vector_name = "EB66+", DO_EV4_MMU, DO_DEFAULT_RTC, DO_LCA_IO, DO_LCA_BUS, - machine_check: lca_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 35, - device_interrupt: cabriolet_device_interrupt, - - init_arch: lca_init_arch, - init_irq: cabriolet_init_irq, - init_rtc: common_init_rtc, - init_pci: cabriolet_init_pci, - pci_map_irq: eb66p_map_irq, - pci_swizzle: common_swizzle, + .machine_check = lca_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 35, + .device_interrupt = cabriolet_device_interrupt, + + .init_arch = lca_init_arch, + .init_irq = cabriolet_init_irq, + .init_rtc = common_init_rtc, + .init_pci = cabriolet_init_pci, + .pci_map_irq = eb66p_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(eb66p) #endif #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164) struct alpha_machine_vector lx164_mv __initmv = { - vector_name: "LX164", + .vector_name = "LX164", DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: PYXIS_DAC_OFFSET, - - nr_irqs: 35, - device_interrupt: cabriolet_device_interrupt, - - init_arch: pyxis_init_arch, - init_irq: cabriolet_init_irq, - init_rtc: common_init_rtc, - init_pci: alphapc164_init_pci, - pci_map_irq: alphapc164_map_irq, - pci_swizzle: common_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = PYXIS_DAC_OFFSET, + + .nr_irqs = 35, + .device_interrupt = cabriolet_device_interrupt, + + .init_arch = pyxis_init_arch, + .init_irq = cabriolet_init_irq, + .init_rtc = common_init_rtc, + .init_pci = alphapc164_init_pci, + .pci_map_irq = alphapc164_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(lx164) #endif #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164) struct alpha_machine_vector pc164_mv __initmv = { - vector_name: "PC164", + .vector_name = "PC164", DO_EV5_MMU, DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: CIA_DEFAULT_MEM_BASE, - - nr_irqs: 35, - device_interrupt: pc164_device_interrupt, - - init_arch: cia_init_arch, - init_irq: pc164_init_irq, - init_rtc: common_init_rtc, - init_pci: alphapc164_init_pci, - pci_map_irq: alphapc164_map_irq, - pci_swizzle: common_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = CIA_DEFAULT_MEM_BASE, + + .nr_irqs = 35, + .device_interrupt = pc164_device_interrupt, + + .init_arch = cia_init_arch, + .init_irq = pc164_init_irq, + .init_rtc = common_init_rtc, + .init_pci = alphapc164_init_pci, + .pci_map_irq = alphapc164_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(pc164) #endif diff -Nru a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c --- a/arch/alpha/kernel/sys_dp264.c Tue Oct 15 20:29:12 2002 +++ b/arch/alpha/kernel/sys_dp264.c Tue Oct 15 20:29:12 2002 @@ -197,25 +197,25 @@ } static struct hw_interrupt_type dp264_irq_type = { - typename: "DP264", - startup: dp264_startup_irq, - shutdown: dp264_disable_irq, - enable: dp264_enable_irq, - disable: dp264_disable_irq, - ack: dp264_disable_irq, - end: dp264_end_irq, - set_affinity: dp264_set_affinity, + .typename = "DP264", + .startup = dp264_startup_irq, + .shutdown = dp264_disable_irq, + .enable = dp264_enable_irq, + .disable = dp264_disable_irq, + .ack = dp264_disable_irq, + .end = dp264_end_irq, + .set_affinity = dp264_set_affinity, }; static struct hw_interrupt_type clipper_irq_type = { - typename: "CLIPPER", - startup: clipper_startup_irq, - shutdown: clipper_disable_irq, - enable: clipper_enable_irq, - disable: clipper_disable_irq, - ack: clipper_disable_irq, - end: clipper_end_irq, - set_affinity: clipper_set_affinity, + .typename = "CLIPPER", + .startup = clipper_startup_irq, + .shutdown = clipper_disable_irq, + .enable = clipper_enable_irq, + .disable = clipper_disable_irq, + .ack = clipper_disable_irq, + .end = clipper_end_irq, + .set_affinity = clipper_set_affinity, }; static void @@ -566,100 +566,100 @@ */ struct alpha_machine_vector dp264_mv __initmv = { - vector_name: "DP264", + .vector_name = "DP264", DO_EV6_MMU, DO_DEFAULT_RTC, DO_TSUNAMI_IO, DO_TSUNAMI_BUS, - machine_check: tsunami_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: TSUNAMI_DAC_OFFSET, - - nr_irqs: 64, - device_interrupt: dp264_device_interrupt, - - init_arch: tsunami_init_arch, - init_irq: dp264_init_irq, - init_rtc: common_init_rtc, - init_pci: dp264_init_pci, - kill_arch: tsunami_kill_arch, - pci_map_irq: dp264_map_irq, - pci_swizzle: common_swizzle, + .machine_check = tsunami_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = TSUNAMI_DAC_OFFSET, + + .nr_irqs = 64, + .device_interrupt = dp264_device_interrupt, + + .init_arch = tsunami_init_arch, + .init_irq = dp264_init_irq, + .init_rtc = common_init_rtc, + .init_pci = dp264_init_pci, + .kill_arch = tsunami_kill_arch, + .pci_map_irq = dp264_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(dp264) struct alpha_machine_vector monet_mv __initmv = { - vector_name: "Monet", + .vector_name = "Monet", DO_EV6_MMU, DO_DEFAULT_RTC, DO_TSUNAMI_IO, DO_TSUNAMI_BUS, - machine_check: tsunami_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: TSUNAMI_DAC_OFFSET, - - nr_irqs: 64, - device_interrupt: dp264_device_interrupt, - - init_arch: tsunami_init_arch, - init_irq: dp264_init_irq, - init_rtc: common_init_rtc, - init_pci: monet_init_pci, - kill_arch: tsunami_kill_arch, - pci_map_irq: monet_map_irq, - pci_swizzle: monet_swizzle, + .machine_check = tsunami_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = TSUNAMI_DAC_OFFSET, + + .nr_irqs = 64, + .device_interrupt = dp264_device_interrupt, + + .init_arch = tsunami_init_arch, + .init_irq = dp264_init_irq, + .init_rtc = common_init_rtc, + .init_pci = monet_init_pci, + .kill_arch = tsunami_kill_arch, + .pci_map_irq = monet_map_irq, + .pci_swizzle = monet_swizzle, }; struct alpha_machine_vector webbrick_mv __initmv = { - vector_name: "Webbrick", + .vector_name = "Webbrick", DO_EV6_MMU, DO_DEFAULT_RTC, DO_TSUNAMI_IO, DO_TSUNAMI_BUS, - machine_check: tsunami_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: TSUNAMI_DAC_OFFSET, - - nr_irqs: 64, - device_interrupt: dp264_device_interrupt, - - init_arch: webbrick_init_arch, - init_irq: dp264_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: tsunami_kill_arch, - pci_map_irq: webbrick_map_irq, - pci_swizzle: common_swizzle, + .machine_check = tsunami_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = TSUNAMI_DAC_OFFSET, + + .nr_irqs = 64, + .device_interrupt = dp264_device_interrupt, + + .init_arch = webbrick_init_arch, + .init_irq = dp264_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = tsunami_kill_arch, + .pci_map_irq = webbrick_map_irq, + .pci_swizzle = common_swizzle, }; struct alpha_machine_vector clipper_mv __initmv = { - vector_name: "Clipper", + .vector_name = "Clipper", DO_EV6_MMU, DO_DEFAULT_RTC, DO_TSUNAMI_IO, DO_TSUNAMI_BUS, - machine_check: tsunami_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: TSUNAMI_DAC_OFFSET, - - nr_irqs: 64, - device_interrupt: dp264_device_interrupt, - - init_arch: tsunami_init_arch, - init_irq: clipper_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: tsunami_kill_arch, - pci_map_irq: clipper_map_irq, - pci_swizzle: common_swizzle, + .machine_check = tsunami_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = TSUNAMI_DAC_OFFSET, + + .nr_irqs = 64, + .device_interrupt = dp264_device_interrupt, + + .init_arch = tsunami_init_arch, + .init_irq = clipper_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = tsunami_kill_arch, + .pci_map_irq = clipper_map_irq, + .pci_swizzle = common_swizzle, }; /* Sharks strongly resemble Clipper, at least as far @@ -668,27 +668,27 @@ */ struct alpha_machine_vector shark_mv __initmv = { - vector_name: "Shark", + .vector_name = "Shark", DO_EV6_MMU, DO_DEFAULT_RTC, DO_TSUNAMI_IO, DO_TSUNAMI_BUS, - machine_check: tsunami_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: TSUNAMI_DAC_OFFSET, - - nr_irqs: 64, - device_interrupt: dp264_device_interrupt, - - init_arch: tsunami_init_arch, - init_irq: clipper_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: tsunami_kill_arch, - pci_map_irq: clipper_map_irq, - pci_swizzle: common_swizzle, + .machine_check = tsunami_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = TSUNAMI_DAC_OFFSET, + + .nr_irqs = 64, + .device_interrupt = dp264_device_interrupt, + + .init_arch = tsunami_init_arch, + .init_irq = clipper_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = tsunami_kill_arch, + .pci_map_irq = clipper_map_irq, + .pci_swizzle = common_swizzle, }; /* No alpha_mv alias for webbrick/monet/clipper, since we compile them diff -Nru a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c --- a/arch/alpha/kernel/sys_eb64p.c Tue Oct 15 20:29:19 2002 +++ b/arch/alpha/kernel/sys_eb64p.c Tue Oct 15 20:29:19 2002 @@ -71,13 +71,13 @@ } static struct hw_interrupt_type eb64p_irq_type = { - typename: "EB64P", - startup: eb64p_startup_irq, - shutdown: eb64p_disable_irq, - enable: eb64p_enable_irq, - disable: eb64p_disable_irq, - ack: eb64p_disable_irq, - end: eb64p_end_irq, + .typename = "EB64P", + .startup = eb64p_startup_irq, + .shutdown = eb64p_disable_irq, + .enable = eb64p_enable_irq, + .disable = eb64p_disable_irq, + .ack = eb64p_disable_irq, + .end = eb64p_end_irq, }; static void @@ -208,51 +208,51 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB64P) struct alpha_machine_vector eb64p_mv __initmv = { - vector_name: "EB64+", + .vector_name = "EB64+", DO_EV4_MMU, DO_DEFAULT_RTC, DO_APECS_IO, DO_APECS_BUS, - machine_check: apecs_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 32, - device_interrupt: eb64p_device_interrupt, - - init_arch: apecs_init_arch, - init_irq: eb64p_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: NULL, - pci_map_irq: eb64p_map_irq, - pci_swizzle: common_swizzle, + .machine_check = apecs_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 32, + .device_interrupt = eb64p_device_interrupt, + + .init_arch = apecs_init_arch, + .init_irq = eb64p_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = NULL, + .pci_map_irq = eb64p_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(eb64p) #endif #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66) struct alpha_machine_vector eb66_mv __initmv = { - vector_name: "EB66", + .vector_name = "EB66", DO_EV4_MMU, DO_DEFAULT_RTC, DO_LCA_IO, DO_LCA_BUS, - machine_check: lca_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 32, - device_interrupt: eb64p_device_interrupt, - - init_arch: lca_init_arch, - init_irq: eb64p_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - pci_map_irq: eb64p_map_irq, - pci_swizzle: common_swizzle, + .machine_check = lca_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 32, + .device_interrupt = eb64p_device_interrupt, + + .init_arch = lca_init_arch, + .init_irq = eb64p_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .pci_map_irq = eb64p_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(eb66) #endif diff -Nru a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c --- a/arch/alpha/kernel/sys_eiger.c Tue Oct 15 20:29:12 2002 +++ b/arch/alpha/kernel/sys_eiger.c Tue Oct 15 20:29:12 2002 @@ -81,13 +81,13 @@ } static struct hw_interrupt_type eiger_irq_type = { - typename: "EIGER", - startup: eiger_startup_irq, - shutdown: eiger_disable_irq, - enable: eiger_enable_irq, - disable: eiger_disable_irq, - ack: eiger_disable_irq, - end: eiger_end_irq, + .typename = "EIGER", + .startup = eiger_startup_irq, + .shutdown = eiger_disable_irq, + .enable = eiger_enable_irq, + .disable = eiger_disable_irq, + .ack = eiger_disable_irq, + .end = eiger_end_irq, }; static void @@ -225,26 +225,26 @@ */ struct alpha_machine_vector eiger_mv __initmv = { - vector_name: "Eiger", + .vector_name = "Eiger", DO_EV6_MMU, DO_DEFAULT_RTC, DO_TSUNAMI_IO, DO_TSUNAMI_BUS, - machine_check: tsunami_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: TSUNAMI_DAC_OFFSET, - - nr_irqs: 128, - device_interrupt: eiger_device_interrupt, - - init_arch: tsunami_init_arch, - init_irq: eiger_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: tsunami_kill_arch, - pci_map_irq: eiger_map_irq, - pci_swizzle: eiger_swizzle, + .machine_check = tsunami_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = TSUNAMI_DAC_OFFSET, + + .nr_irqs = 128, + .device_interrupt = eiger_device_interrupt, + + .init_arch = tsunami_init_arch, + .init_irq = eiger_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = tsunami_kill_arch, + .pci_map_irq = eiger_map_irq, + .pci_swizzle = eiger_swizzle, }; ALIAS_MV(eiger) diff -Nru a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c --- a/arch/alpha/kernel/sys_jensen.c Tue Oct 15 20:29:17 2002 +++ b/arch/alpha/kernel/sys_jensen.c Tue Oct 15 20:29:17 2002 @@ -119,13 +119,13 @@ } static struct hw_interrupt_type jensen_local_irq_type = { - typename: "LOCAL", - startup: jensen_local_startup, - shutdown: jensen_local_shutdown, - enable: jensen_local_enable, - disable: jensen_local_disable, - ack: jensen_local_ack, - end: jensen_local_end, + .typename = "LOCAL", + .startup = jensen_local_startup, + .shutdown = jensen_local_shutdown, + .enable = jensen_local_enable, + .disable = jensen_local_disable, + .ack = jensen_local_ack, + .end = jensen_local_end, }; static void @@ -252,21 +252,21 @@ */ struct alpha_machine_vector jensen_mv __initmv = { - vector_name: "Jensen", + .vector_name = "Jensen", DO_EV4_MMU, IO_LITE(JENSEN,jensen), BUS(jensen), - machine_check: jensen_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - rtc_port: 0x170, - - nr_irqs: 16, - device_interrupt: jensen_device_interrupt, - - init_arch: jensen_init_arch, - init_irq: jensen_init_irq, - init_rtc: common_init_rtc, - init_pci: NULL, - kill_arch: NULL, + .machine_check = jensen_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .rtc_port = 0x170, + + .nr_irqs = 16, + .device_interrupt = jensen_device_interrupt, + + .init_arch = jensen_init_arch, + .init_irq = jensen_init_irq, + .init_rtc = common_init_rtc, + .init_pci = NULL, + .kill_arch = NULL, }; ALIAS_MV(jensen) diff -Nru a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c --- a/arch/alpha/kernel/sys_miata.c Tue Oct 15 20:29:17 2002 +++ b/arch/alpha/kernel/sys_miata.c Tue Oct 15 20:29:17 2002 @@ -261,26 +261,26 @@ */ struct alpha_machine_vector miata_mv __initmv = { - vector_name: "Miata", + .vector_name = "Miata", DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: PYXIS_DAC_OFFSET, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = PYXIS_DAC_OFFSET, - nr_irqs: 48, - device_interrupt: pyxis_device_interrupt, + .nr_irqs = 48, + .device_interrupt = pyxis_device_interrupt, - init_arch: pyxis_init_arch, - init_irq: miata_init_irq, - init_rtc: common_init_rtc, - init_pci: miata_init_pci, - kill_arch: miata_kill_arch, - pci_map_irq: miata_map_irq, - pci_swizzle: miata_swizzle, + .init_arch = pyxis_init_arch, + .init_irq = miata_init_irq, + .init_rtc = common_init_rtc, + .init_pci = miata_init_pci, + .kill_arch = miata_kill_arch, + .pci_map_irq = miata_map_irq, + .pci_swizzle = miata_swizzle, }; ALIAS_MV(miata) diff -Nru a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c --- a/arch/alpha/kernel/sys_mikasa.c Tue Oct 15 20:29:19 2002 +++ b/arch/alpha/kernel/sys_mikasa.c Tue Oct 15 20:29:20 2002 @@ -70,13 +70,13 @@ } static struct hw_interrupt_type mikasa_irq_type = { - typename: "MIKASA", - startup: mikasa_startup_irq, - shutdown: mikasa_disable_irq, - enable: mikasa_enable_irq, - disable: mikasa_disable_irq, - ack: mikasa_disable_irq, - end: mikasa_end_irq, + .typename = "MIKASA", + .startup = mikasa_startup_irq, + .shutdown = mikasa_disable_irq, + .enable = mikasa_enable_irq, + .disable = mikasa_disable_irq, + .ack = mikasa_disable_irq, + .end = mikasa_end_irq, }; static void @@ -217,51 +217,51 @@ #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) struct alpha_machine_vector mikasa_mv __initmv = { - vector_name: "Mikasa", + .vector_name = "Mikasa", DO_EV4_MMU, DO_DEFAULT_RTC, DO_APECS_IO, DO_APECS_BUS, - machine_check: mikasa_apecs_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 32, - device_interrupt: mikasa_device_interrupt, - - init_arch: apecs_init_arch, - init_irq: mikasa_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: NULL, - pci_map_irq: mikasa_map_irq, - pci_swizzle: common_swizzle, + .machine_check = mikasa_apecs_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 32, + .device_interrupt = mikasa_device_interrupt, + + .init_arch = apecs_init_arch, + .init_irq = mikasa_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = NULL, + .pci_map_irq = mikasa_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(mikasa) #endif #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO) struct alpha_machine_vector mikasa_primo_mv __initmv = { - vector_name: "Mikasa-Primo", + .vector_name = "Mikasa-Primo", DO_EV5_MMU, DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: CIA_DEFAULT_MEM_BASE, - - nr_irqs: 32, - device_interrupt: mikasa_device_interrupt, - - init_arch: cia_init_arch, - init_irq: mikasa_init_irq, - init_rtc: common_init_rtc, - init_pci: cia_init_pci, - pci_map_irq: mikasa_map_irq, - pci_swizzle: common_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = CIA_DEFAULT_MEM_BASE, + + .nr_irqs = 32, + .device_interrupt = mikasa_device_interrupt, + + .init_arch = cia_init_arch, + .init_irq = mikasa_init_irq, + .init_rtc = common_init_rtc, + .init_pci = cia_init_pci, + .pci_map_irq = mikasa_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(mikasa_primo) #endif diff -Nru a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c --- a/arch/alpha/kernel/sys_nautilus.c Tue Oct 15 20:29:16 2002 +++ b/arch/alpha/kernel/sys_nautilus.c Tue Oct 15 20:29:16 2002 @@ -510,25 +510,25 @@ */ struct alpha_machine_vector nautilus_mv __initmv = { - vector_name: "Nautilus", + .vector_name = "Nautilus", DO_EV6_MMU, DO_DEFAULT_RTC, DO_IRONGATE_IO, DO_IRONGATE_BUS, - machine_check: nautilus_machine_check, - max_dma_address: ALPHA_NAUTILUS_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: IRONGATE_DEFAULT_MEM_BASE, + .machine_check = nautilus_machine_check, + .max_dma_address = ALPHA_NAUTILUS_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = IRONGATE_DEFAULT_MEM_BASE, - nr_irqs: 16, - device_interrupt: isa_device_interrupt, + .nr_irqs = 16, + .device_interrupt = isa_device_interrupt, - init_arch: irongate_init_arch, - init_irq: nautilus_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: nautilus_kill_arch, - pci_map_irq: nautilus_map_irq, - pci_swizzle: common_swizzle, + .init_arch = irongate_init_arch, + .init_irq = nautilus_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = nautilus_kill_arch, + .pci_map_irq = nautilus_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(nautilus) diff -Nru a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c --- a/arch/alpha/kernel/sys_noritake.c Tue Oct 15 20:29:13 2002 +++ b/arch/alpha/kernel/sys_noritake.c Tue Oct 15 20:29:13 2002 @@ -68,13 +68,13 @@ } static struct hw_interrupt_type noritake_irq_type = { - typename: "NORITAKE", - startup: noritake_startup_irq, - shutdown: noritake_disable_irq, - enable: noritake_enable_irq, - disable: noritake_disable_irq, - ack: noritake_disable_irq, - end: noritake_enable_irq, + .typename = "NORITAKE", + .startup = noritake_startup_irq, + .shutdown = noritake_disable_irq, + .enable = noritake_enable_irq, + .disable = noritake_disable_irq, + .ack = noritake_disable_irq, + .end = noritake_enable_irq, }; static void @@ -299,51 +299,51 @@ #if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO) struct alpha_machine_vector noritake_mv __initmv = { - vector_name: "Noritake", + .vector_name = "Noritake", DO_EV4_MMU, DO_DEFAULT_RTC, DO_APECS_IO, DO_APECS_BUS, - machine_check: noritake_apecs_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: EISA_DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 48, - device_interrupt: noritake_device_interrupt, - - init_arch: apecs_init_arch, - init_irq: noritake_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: NULL, - pci_map_irq: noritake_map_irq, - pci_swizzle: noritake_swizzle, + .machine_check = noritake_apecs_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = EISA_DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 48, + .device_interrupt = noritake_device_interrupt, + + .init_arch = apecs_init_arch, + .init_irq = noritake_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = NULL, + .pci_map_irq = noritake_map_irq, + .pci_swizzle = noritake_swizzle, }; ALIAS_MV(noritake) #endif #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PRIMO) struct alpha_machine_vector noritake_primo_mv __initmv = { - vector_name: "Noritake-Primo", + .vector_name = "Noritake-Primo", DO_EV5_MMU, DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: EISA_DEFAULT_IO_BASE, - min_mem_address: CIA_DEFAULT_MEM_BASE, - - nr_irqs: 48, - device_interrupt: noritake_device_interrupt, - - init_arch: cia_init_arch, - init_irq: noritake_init_irq, - init_rtc: common_init_rtc, - init_pci: cia_init_pci, - pci_map_irq: noritake_map_irq, - pci_swizzle: noritake_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = EISA_DEFAULT_IO_BASE, + .min_mem_address = CIA_DEFAULT_MEM_BASE, + + .nr_irqs = 48, + .device_interrupt = noritake_device_interrupt, + + .init_arch = cia_init_arch, + .init_irq = noritake_init_irq, + .init_rtc = common_init_rtc, + .init_pci = cia_init_pci, + .pci_map_irq = noritake_map_irq, + .pci_swizzle = noritake_swizzle, }; ALIAS_MV(noritake_primo) #endif diff -Nru a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c --- a/arch/alpha/kernel/sys_rawhide.c Tue Oct 15 20:29:21 2002 +++ b/arch/alpha/kernel/sys_rawhide.c Tue Oct 15 20:29:21 2002 @@ -124,13 +124,13 @@ } static struct hw_interrupt_type rawhide_irq_type = { - typename: "RAWHIDE", - startup: rawhide_startup_irq, - shutdown: rawhide_disable_irq, - enable: rawhide_enable_irq, - disable: rawhide_disable_irq, - ack: rawhide_mask_and_ack_irq, - end: rawhide_end_irq, + .typename = "RAWHIDE", + .startup = rawhide_startup_irq, + .shutdown = rawhide_disable_irq, + .enable = rawhide_enable_irq, + .disable = rawhide_disable_irq, + .ack = rawhide_mask_and_ack_irq, + .end = rawhide_end_irq, }; static void @@ -246,26 +246,26 @@ */ struct alpha_machine_vector rawhide_mv __initmv = { - vector_name: "Rawhide", + .vector_name = "Rawhide", DO_EV5_MMU, DO_DEFAULT_RTC, DO_MCPCIA_IO, DO_MCPCIA_BUS, - machine_check: mcpcia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: MCPCIA_DEFAULT_MEM_BASE, - pci_dac_offset: MCPCIA_DAC_OFFSET, - - nr_irqs: 128, - device_interrupt: rawhide_srm_device_interrupt, - - init_arch: mcpcia_init_arch, - init_irq: rawhide_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: NULL, - pci_map_irq: rawhide_map_irq, - pci_swizzle: common_swizzle, + .machine_check = mcpcia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = MCPCIA_DEFAULT_MEM_BASE, + .pci_dac_offset = MCPCIA_DAC_OFFSET, + + .nr_irqs = 128, + .device_interrupt = rawhide_srm_device_interrupt, + + .init_arch = mcpcia_init_arch, + .init_irq = rawhide_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = NULL, + .pci_map_irq = rawhide_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(rawhide) diff -Nru a/arch/alpha/kernel/sys_ruffian.c b/arch/alpha/kernel/sys_ruffian.c --- a/arch/alpha/kernel/sys_ruffian.c Tue Oct 15 20:29:17 2002 +++ b/arch/alpha/kernel/sys_ruffian.c Tue Oct 15 20:29:17 2002 @@ -212,26 +212,26 @@ */ struct alpha_machine_vector ruffian_mv __initmv = { - vector_name: "Ruffian", + .vector_name = "Ruffian", DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_RUFFIAN_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: PYXIS_DAC_OFFSET, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_RUFFIAN_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = PYXIS_DAC_OFFSET, - nr_irqs: 48, - device_interrupt: pyxis_device_interrupt, + .nr_irqs = 48, + .device_interrupt = pyxis_device_interrupt, - init_arch: pyxis_init_arch, - init_irq: ruffian_init_irq, - init_rtc: ruffian_init_rtc, - init_pci: cia_init_pci, - kill_arch: ruffian_kill_arch, - pci_map_irq: ruffian_map_irq, - pci_swizzle: ruffian_swizzle, + .init_arch = pyxis_init_arch, + .init_irq = ruffian_init_irq, + .init_rtc = ruffian_init_rtc, + .init_pci = cia_init_pci, + .kill_arch = ruffian_kill_arch, + .pci_map_irq = ruffian_map_irq, + .pci_swizzle = ruffian_swizzle, }; ALIAS_MV(ruffian) diff -Nru a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c --- a/arch/alpha/kernel/sys_rx164.c Tue Oct 15 20:29:11 2002 +++ b/arch/alpha/kernel/sys_rx164.c Tue Oct 15 20:29:11 2002 @@ -73,13 +73,13 @@ } static struct hw_interrupt_type rx164_irq_type = { - typename: "RX164", - startup: rx164_startup_irq, - shutdown: rx164_disable_irq, - enable: rx164_enable_irq, - disable: rx164_disable_irq, - ack: rx164_disable_irq, - end: rx164_end_irq, + .typename = "RX164", + .startup = rx164_startup_irq, + .shutdown = rx164_disable_irq, + .enable = rx164_enable_irq, + .disable = rx164_disable_irq, + .ack = rx164_disable_irq, + .end = rx164_end_irq, }; static void @@ -197,25 +197,25 @@ */ struct alpha_machine_vector rx164_mv __initmv = { - vector_name: "RX164", + .vector_name = "RX164", DO_EV5_MMU, DO_DEFAULT_RTC, DO_POLARIS_IO, DO_POLARIS_BUS, - machine_check: polaris_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - - nr_irqs: 40, - device_interrupt: rx164_device_interrupt, - - init_arch: polaris_init_arch, - init_irq: rx164_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: NULL, - pci_map_irq: rx164_map_irq, - pci_swizzle: common_swizzle, + .machine_check = polaris_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + + .nr_irqs = 40, + .device_interrupt = rx164_device_interrupt, + + .init_arch = polaris_init_arch, + .init_irq = rx164_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = NULL, + .pci_map_irq = rx164_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(rx164) diff -Nru a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c --- a/arch/alpha/kernel/sys_sable.c Tue Oct 15 20:29:12 2002 +++ b/arch/alpha/kernel/sys_sable.c Tue Oct 15 20:29:12 2002 @@ -185,13 +185,13 @@ } static struct hw_interrupt_type sable_irq_type = { - typename: "SABLE", - startup: sable_startup_irq, - shutdown: sable_disable_irq, - enable: sable_enable_irq, - disable: sable_disable_irq, - ack: sable_mask_and_ack_irq, - end: sable_end_irq, + .typename = "SABLE", + .startup = sable_startup_irq, + .shutdown = sable_disable_irq, + .enable = sable_enable_irq, + .disable = sable_disable_irq, + .ack = sable_mask_and_ack_irq, + .end = sable_end_irq, }; static void @@ -284,29 +284,29 @@ #undef GAMMA_BIAS #define GAMMA_BIAS 0 struct alpha_machine_vector sable_mv __initmv = { - vector_name: "Sable", + .vector_name = "Sable", DO_EV4_MMU, DO_DEFAULT_RTC, DO_T2_IO, DO_T2_BUS, - machine_check: t2_machine_check, - max_dma_address: ALPHA_SABLE_MAX_DMA_ADDRESS, - min_io_address: EISA_DEFAULT_IO_BASE, - min_mem_address: T2_DEFAULT_MEM_BASE, - - nr_irqs: 40, - device_interrupt: sable_srm_device_interrupt, - - init_arch: t2_init_arch, - init_irq: sable_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: NULL, - pci_map_irq: sable_map_irq, - pci_swizzle: common_swizzle, + .machine_check = t2_machine_check, + .max_dma_address = ALPHA_SABLE_MAX_DMA_ADDRESS, + .min_io_address = EISA_DEFAULT_IO_BASE, + .min_mem_address = T2_DEFAULT_MEM_BASE, + + .nr_irqs = 40, + .device_interrupt = sable_srm_device_interrupt, + + .init_arch = t2_init_arch, + .init_irq = sable_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = NULL, + .pci_map_irq = sable_map_irq, + .pci_swizzle = common_swizzle, - sys: { t2: { - gamma_bias: 0 + .sys = { .t2 = { + .gamma_bias = 0 } } }; ALIAS_MV(sable) @@ -316,28 +316,28 @@ #undef GAMMA_BIAS #define GAMMA_BIAS _GAMMA_BIAS struct alpha_machine_vector sable_gamma_mv __initmv = { - vector_name: "Sable-Gamma", + .vector_name = "Sable-Gamma", DO_EV5_MMU, DO_DEFAULT_RTC, DO_T2_IO, DO_T2_BUS, - machine_check: t2_machine_check, - max_dma_address: ALPHA_SABLE_MAX_DMA_ADDRESS, - min_io_address: EISA_DEFAULT_IO_BASE, - min_mem_address: T2_DEFAULT_MEM_BASE, - - nr_irqs: 40, - device_interrupt: sable_srm_device_interrupt, - - init_arch: t2_init_arch, - init_irq: sable_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - pci_map_irq: sable_map_irq, - pci_swizzle: common_swizzle, + .machine_check = t2_machine_check, + .max_dma_address = ALPHA_SABLE_MAX_DMA_ADDRESS, + .min_io_address = EISA_DEFAULT_IO_BASE, + .min_mem_address = T2_DEFAULT_MEM_BASE, + + .nr_irqs = 40, + .device_interrupt = sable_srm_device_interrupt, + + .init_arch = t2_init_arch, + .init_irq = sable_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .pci_map_irq = sable_map_irq, + .pci_swizzle = common_swizzle, - sys: { t2: { - gamma_bias: _GAMMA_BIAS + .sys = { .t2 = { + .gamma_bias = _GAMMA_BIAS } } }; ALIAS_MV(sable_gamma) diff -Nru a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c --- a/arch/alpha/kernel/sys_sio.c Tue Oct 15 20:29:11 2002 +++ b/arch/alpha/kernel/sys_sio.c Tue Oct 15 20:29:11 2002 @@ -252,30 +252,30 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_BOOK1) struct alpha_machine_vector alphabook1_mv __initmv = { - vector_name: "AlphaBook1", + .vector_name = "AlphaBook1", DO_EV4_MMU, DO_DEFAULT_RTC, DO_LCA_IO, DO_LCA_BUS, - machine_check: lca_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 16, - device_interrupt: isa_device_interrupt, - - init_arch: alphabook1_init_arch, - init_irq: sio_init_irq, - init_rtc: common_init_rtc, - init_pci: alphabook1_init_pci, - kill_arch: NULL, - pci_map_irq: noname_map_irq, - pci_swizzle: common_swizzle, + .machine_check = lca_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 16, + .device_interrupt = isa_device_interrupt, + + .init_arch = alphabook1_init_arch, + .init_irq = sio_init_irq, + .init_rtc = common_init_rtc, + .init_pci = alphabook1_init_pci, + .kill_arch = NULL, + .pci_map_irq = noname_map_irq, + .pci_swizzle = common_swizzle, - sys: { sio: { + .sys = { .sio = { /* NCR810 SCSI is 14, PCMCIA controller is 15. */ - route_tab: 0x0e0f0a0a, + .route_tab = 0x0e0f0a0a, }} }; ALIAS_MV(alphabook1) @@ -283,28 +283,28 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_AVANTI) struct alpha_machine_vector avanti_mv __initmv = { - vector_name: "Avanti", + .vector_name = "Avanti", DO_EV4_MMU, DO_DEFAULT_RTC, DO_APECS_IO, DO_APECS_BUS, - machine_check: apecs_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 16, - device_interrupt: isa_device_interrupt, - - init_arch: apecs_init_arch, - init_irq: sio_init_irq, - init_rtc: common_init_rtc, - init_pci: noname_init_pci, - pci_map_irq: noname_map_irq, - pci_swizzle: common_swizzle, + .machine_check = apecs_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 16, + .device_interrupt = isa_device_interrupt, + + .init_arch = apecs_init_arch, + .init_irq = sio_init_irq, + .init_rtc = common_init_rtc, + .init_pci = noname_init_pci, + .pci_map_irq = noname_map_irq, + .pci_swizzle = common_swizzle, - sys: { sio: { - route_tab: 0x0b0a0e0f, + .sys = { .sio = { + .route_tab = 0x0b0a0e0f, }} }; ALIAS_MV(avanti) @@ -312,27 +312,27 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_NONAME) struct alpha_machine_vector noname_mv __initmv = { - vector_name: "Noname", + .vector_name = "Noname", DO_EV4_MMU, DO_DEFAULT_RTC, DO_LCA_IO, DO_LCA_BUS, - machine_check: lca_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 16, - device_interrupt: srm_device_interrupt, - - init_arch: lca_init_arch, - init_irq: sio_init_irq, - init_rtc: common_init_rtc, - init_pci: noname_init_pci, - pci_map_irq: noname_map_irq, - pci_swizzle: common_swizzle, + .machine_check = lca_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 16, + .device_interrupt = srm_device_interrupt, + + .init_arch = lca_init_arch, + .init_irq = sio_init_irq, + .init_rtc = common_init_rtc, + .init_pci = noname_init_pci, + .pci_map_irq = noname_map_irq, + .pci_swizzle = common_swizzle, - sys: { sio: { + .sys = { .sio = { /* For UDB, the only available PCI slot must not map to IRQ 9, since that's the builtin MSS sound chip. That PCI slot will map to PIRQ1 (for INTA at least), so we give it IRQ 15 @@ -342,7 +342,7 @@ they are co-indicated when the platform type "Noname" is selected... :-( */ - route_tab: 0x0b0a0f0d, + .route_tab = 0x0b0a0f0d, }} }; ALIAS_MV(noname) @@ -350,28 +350,28 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_P2K) struct alpha_machine_vector p2k_mv __initmv = { - vector_name: "Platform2000", + .vector_name = "Platform2000", DO_EV4_MMU, DO_DEFAULT_RTC, DO_LCA_IO, DO_LCA_BUS, - machine_check: lca_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, - - nr_irqs: 16, - device_interrupt: srm_device_interrupt, - - init_arch: lca_init_arch, - init_irq: sio_init_irq, - init_rtc: common_init_rtc, - init_pci: noname_init_pci, - pci_map_irq: p2k_map_irq, - pci_swizzle: common_swizzle, + .machine_check = lca_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = APECS_AND_LCA_DEFAULT_MEM_BASE, + + .nr_irqs = 16, + .device_interrupt = srm_device_interrupt, + + .init_arch = lca_init_arch, + .init_irq = sio_init_irq, + .init_rtc = common_init_rtc, + .init_pci = noname_init_pci, + .pci_map_irq = p2k_map_irq, + .pci_swizzle = common_swizzle, - sys: { sio: { - route_tab: 0x0b0a090f, + .sys = { .sio = { + .route_tab = 0x0b0a090f, }} }; ALIAS_MV(p2k) @@ -379,28 +379,28 @@ #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_XL) struct alpha_machine_vector xl_mv __initmv = { - vector_name: "XL", + .vector_name = "XL", DO_EV4_MMU, DO_DEFAULT_RTC, DO_APECS_IO, BUS(apecs), - machine_check: apecs_machine_check, - max_dma_address: ALPHA_XL_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: XL_DEFAULT_MEM_BASE, - - nr_irqs: 16, - device_interrupt: isa_device_interrupt, - - init_arch: apecs_init_arch, - init_irq: sio_init_irq, - init_rtc: common_init_rtc, - init_pci: noname_init_pci, - pci_map_irq: noname_map_irq, - pci_swizzle: common_swizzle, + .machine_check = apecs_machine_check, + .max_dma_address = ALPHA_XL_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = XL_DEFAULT_MEM_BASE, + + .nr_irqs = 16, + .device_interrupt = isa_device_interrupt, + + .init_arch = apecs_init_arch, + .init_irq = sio_init_irq, + .init_rtc = common_init_rtc, + .init_pci = noname_init_pci, + .pci_map_irq = noname_map_irq, + .pci_swizzle = common_swizzle, - sys: { sio: { - route_tab: 0x0b0a090f, + .sys = { .sio = { + .route_tab = 0x0b0a090f, }} }; ALIAS_MV(xl) diff -Nru a/arch/alpha/kernel/sys_sx164.c b/arch/alpha/kernel/sys_sx164.c --- a/arch/alpha/kernel/sys_sx164.c Tue Oct 15 20:29:17 2002 +++ b/arch/alpha/kernel/sys_sx164.c Tue Oct 15 20:29:17 2002 @@ -154,26 +154,26 @@ */ struct alpha_machine_vector sx164_mv __initmv = { - vector_name: "SX164", + .vector_name = "SX164", DO_EV5_MMU, DO_DEFAULT_RTC, DO_PYXIS_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: PYXIS_DAC_OFFSET, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = PYXIS_DAC_OFFSET, - nr_irqs: 48, - device_interrupt: pyxis_device_interrupt, + .nr_irqs = 48, + .device_interrupt = pyxis_device_interrupt, - init_arch: sx164_init_arch, - init_irq: sx164_init_irq, - init_rtc: common_init_rtc, - init_pci: sx164_init_pci, - kill_arch: NULL, - pci_map_irq: sx164_map_irq, - pci_swizzle: common_swizzle, + .init_arch = sx164_init_arch, + .init_irq = sx164_init_irq, + .init_rtc = common_init_rtc, + .init_pci = sx164_init_pci, + .kill_arch = NULL, + .pci_map_irq = sx164_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(sx164) diff -Nru a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c --- a/arch/alpha/kernel/sys_takara.c Tue Oct 15 20:29:12 2002 +++ b/arch/alpha/kernel/sys_takara.c Tue Oct 15 20:29:12 2002 @@ -75,13 +75,13 @@ } static struct hw_interrupt_type takara_irq_type = { - typename: "TAKARA", - startup: takara_startup_irq, - shutdown: takara_disable_irq, - enable: takara_enable_irq, - disable: takara_disable_irq, - ack: takara_disable_irq, - end: takara_end_irq, + .typename = "TAKARA", + .startup = takara_startup_irq, + .shutdown = takara_disable_irq, + .enable = takara_enable_irq, + .disable = takara_disable_irq, + .ack = takara_disable_irq, + .end = takara_end_irq, }; static void @@ -269,25 +269,25 @@ */ struct alpha_machine_vector takara_mv __initmv = { - vector_name: "Takara", + .vector_name = "Takara", DO_EV5_MMU, DO_DEFAULT_RTC, DO_CIA_IO, DO_CIA_BUS, - machine_check: cia_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: CIA_DEFAULT_MEM_BASE, - - nr_irqs: 128, - device_interrupt: takara_device_interrupt, - - init_arch: cia_init_arch, - init_irq: takara_init_irq, - init_rtc: common_init_rtc, - init_pci: takara_init_pci, - kill_arch: NULL, - pci_map_irq: takara_map_irq, - pci_swizzle: takara_swizzle, + .machine_check = cia_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = CIA_DEFAULT_MEM_BASE, + + .nr_irqs = 128, + .device_interrupt = takara_device_interrupt, + + .init_arch = cia_init_arch, + .init_irq = takara_init_irq, + .init_rtc = common_init_rtc, + .init_pci = takara_init_pci, + .kill_arch = NULL, + .pci_map_irq = takara_map_irq, + .pci_swizzle = takara_swizzle, }; ALIAS_MV(takara) diff -Nru a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c --- a/arch/alpha/kernel/sys_titan.c Tue Oct 15 20:29:21 2002 +++ b/arch/alpha/kernel/sys_titan.c Tue Oct 15 20:29:21 2002 @@ -152,14 +152,14 @@ } static struct hw_interrupt_type privateer_irq_type = { - typename: "PRIVATEER", - startup: privateer_startup_irq, - shutdown: privateer_disable_irq, - enable: privateer_enable_irq, - disable: privateer_disable_irq, - ack: privateer_disable_irq, - end: privateer_end_irq, - set_affinity: privateer_set_affinity, + .typename = "PRIVATEER", + .startup = privateer_startup_irq, + .shutdown = privateer_disable_irq, + .enable = privateer_enable_irq, + .disable = privateer_disable_irq, + .ack = privateer_disable_irq, + .end = privateer_end_irq, + .set_affinity = privateer_set_affinity, }; static void @@ -367,26 +367,26 @@ */ struct alpha_machine_vector privateer_mv __initmv = { - vector_name: "PRIVATEER", + .vector_name = "PRIVATEER", DO_EV6_MMU, DO_DEFAULT_RTC, DO_TITAN_IO, DO_TITAN_BUS, - machine_check: privateer_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - pci_dac_offset: TITAN_DAC_OFFSET, - - nr_irqs: 80, /* 64 + 16 */ - device_interrupt: privateer_device_interrupt, - - init_arch: titan_init_arch, - init_irq: privateer_init_irq, - init_rtc: common_init_rtc, - init_pci: privateer_init_pci, - kill_arch: titan_kill_arch, - pci_map_irq: privateer_map_irq, - pci_swizzle: common_swizzle, + .machine_check = privateer_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + .pci_dac_offset = TITAN_DAC_OFFSET, + + .nr_irqs = 80, /* 64 + 16 */ + .device_interrupt = privateer_device_interrupt, + + .init_arch = titan_init_arch, + .init_irq = privateer_init_irq, + .init_rtc = common_init_rtc, + .init_pci = privateer_init_pci, + .kill_arch = titan_kill_arch, + .pci_map_irq = privateer_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(privateer) diff -Nru a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c --- a/arch/alpha/kernel/sys_wildfire.c Tue Oct 15 20:29:16 2002 +++ b/arch/alpha/kernel/sys_wildfire.c Tue Oct 15 20:29:16 2002 @@ -158,13 +158,13 @@ } static struct hw_interrupt_type wildfire_irq_type = { - typename: "WILDFIRE", - startup: wildfire_startup_irq, - shutdown: wildfire_disable_irq, - enable: wildfire_enable_irq, - disable: wildfire_disable_irq, - ack: wildfire_mask_and_ack_irq, - end: wildfire_end_irq, + .typename = "WILDFIRE", + .startup = wildfire_startup_irq, + .shutdown = wildfire_disable_irq, + .enable = wildfire_enable_irq, + .disable = wildfire_disable_irq, + .ack = wildfire_mask_and_ack_irq, + .end = wildfire_end_irq, }; static void __init @@ -173,8 +173,8 @@ int i, irq_bias; unsigned long io_bias; static struct irqaction isa_enable = { - handler: no_action, - name: "isa_enable", + .handler = no_action, + .name = "isa_enable", }; irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA) @@ -333,25 +333,25 @@ */ struct alpha_machine_vector wildfire_mv __initmv = { - vector_name: "WILDFIRE", + .vector_name = "WILDFIRE", DO_EV6_MMU, DO_DEFAULT_RTC, DO_WILDFIRE_IO, DO_WILDFIRE_BUS, - machine_check: wildfire_machine_check, - max_dma_address: ALPHA_MAX_DMA_ADDRESS, - min_io_address: DEFAULT_IO_BASE, - min_mem_address: DEFAULT_MEM_BASE, - - nr_irqs: WILDFIRE_NR_IRQS, - device_interrupt: wildfire_device_interrupt, - - init_arch: wildfire_init_arch, - init_irq: wildfire_init_irq, - init_rtc: common_init_rtc, - init_pci: common_init_pci, - kill_arch: wildfire_kill_arch, - pci_map_irq: wildfire_map_irq, - pci_swizzle: common_swizzle, + .machine_check = wildfire_machine_check, + .max_dma_address = ALPHA_MAX_DMA_ADDRESS, + .min_io_address = DEFAULT_IO_BASE, + .min_mem_address = DEFAULT_MEM_BASE, + + .nr_irqs = WILDFIRE_NR_IRQS, + .device_interrupt = wildfire_device_interrupt, + + .init_arch = wildfire_init_arch, + .init_irq = wildfire_init_irq, + .init_rtc = common_init_rtc, + .init_pci = common_init_pci, + .kill_arch = wildfire_kill_arch, + .pci_map_irq = wildfire_map_irq, + .pci_swizzle = common_swizzle, }; ALIAS_MV(wildfire) diff -Nru a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S --- a/arch/alpha/kernel/systbls.S Tue Oct 15 20:29:17 2002 +++ b/arch/alpha/kernel/systbls.S Tue Oct 15 20:29:17 2002 @@ -4,6 +4,7 @@ * The system call table. */ +#include /* CONFIG_OSF4_COMPAT */ #include .data diff -Nru a/arch/alpha/lib/ev6-stxncpy.S b/arch/alpha/lib/ev6-stxncpy.S --- a/arch/alpha/lib/ev6-stxncpy.S Tue Oct 15 20:29:20 2002 +++ b/arch/alpha/lib/ev6-stxncpy.S Tue Oct 15 20:29:20 2002 @@ -253,7 +253,7 @@ stq_u t0, -8(a0) # U : save the current word beq a2, $u_eoc # U : - ldq_u t2, 0(a1) # U : Latency=3 load high word for next time + ldq_u t2, 8(a1) # U : Latency=3 load high word for next time addq a1, 8, a1 # E : extqh t2, a1, t0 # U : extract low bits (2 cycle stall) diff -Nru a/arch/alpha/lib/stxncpy.S b/arch/alpha/lib/stxncpy.S --- a/arch/alpha/lib/stxncpy.S Tue Oct 15 20:29:22 2002 +++ b/arch/alpha/lib/stxncpy.S Tue Oct 15 20:29:22 2002 @@ -210,7 +210,7 @@ addq a0, 8, a0 # .. e1 : extql t2, a1, t1 # e0 : extract high bits for next time beq a2, $u_eoc # .. e1 : - ldq_u t2, 0(a1) # e0 : load high word for next time + ldq_u t2, 8(a1) # e0 : load high word for next time addq a1, 8, a1 # .. e1 : nop # e0 : cmpbge zero, t2, t8 # e1 : test new word for eos (stall) diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile --- a/arch/arm/Makefile Tue Oct 15 20:29:16 2002 +++ b/arch/arm/Makefile Tue Oct 15 20:29:16 2002 @@ -8,6 +8,7 @@ # Copyright (C) 1995-2001 by Russell King LDFLAGS_vmlinux :=-p -X +AFLAGS_vmlinux.lds.o = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) OBJCOPYFLAGS :=-O binary -R .note -R .comment -S GZFLAGS :=-9 #CFLAGS +=-pipe @@ -50,18 +51,29 @@ tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 tune-$(CONFIG_CPU_XSCALE) :=-mtune=strongarm #-mtune=xscale -CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float +# Force -mno-fpu to be passed to the assembler. Some versions of gcc don't +# do this with -msoft-float +CFLAGS_BOOT :=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu +CFLAGS +=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu +AFLAGS +=$(apcs-y) $(arch-y) -mno-fpu -msoft-float -Wa,-mno-fpu ifeq ($(CONFIG_CPU_26),y) PROCESSOR := armo HEAD := arch/arm/mach-arc/head.o arch/arm/kernel/init_task.o + ifeq ($(CONFIG_ROM_KERNEL),y) + DATAADDR = 0x02080000 + TEXTADDR = 0x03800000 + LDSCRIPT = arch/arm/vmlinux-armo-rom.lds.in + else + TEXTADDR = 0x02080000 + LDSCRIPT = arch/arm/vmlinux-armo.lds.in + endif endif ifeq ($(CONFIG_CPU_32),y) PROCESSOR = armv HEAD := arch/arm/kernel/head.o arch/arm/kernel/init_task.o +TEXTADDR = 0xC0008000 endif ifeq ($(CONFIG_ARCH_ARCA5K),y) @@ -175,7 +187,7 @@ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ) drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/ -drivers-$(CONFIG_ARCH_L7200)) += drivers/acorn/char/ +drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/ libs-y += arch/arm/lib/ diff -Nru a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile --- a/arch/arm/boot/compressed/Makefile Tue Oct 15 20:29:12 2002 +++ b/arch/arm/boot/compressed/Makefile Tue Oct 15 20:29:12 2002 @@ -18,7 +18,7 @@ # ifeq ($(CONFIG_ARCH_ACORN),y) OBJS += ll_char_wr.o font.o -ZLDFLAGS += -defsym params=$(PARAMS_PHYS) +CFLAGS += -DPARAMS_PHYS=$(PARAMS_PHYS) endif ifeq ($(CONFIG_ARCH_NETWINDER),y) diff -Nru a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S --- a/arch/arm/boot/compressed/head.S Tue Oct 15 20:29:21 2002 +++ b/arch/arm/boot/compressed/head.S Tue Oct 15 20:29:21 2002 @@ -55,6 +55,18 @@ .macro writeb, rb strb \rb, [r3, #0] .endm +#elif defined(CONFIG_ARCH_SA1100) + .macro loadsp, rb + mov \rb, #0x80000000 @ physical base address +# if defined(CONFIG_DEBUG_LL_SER3) + add \rb, \rb, #0x00050000 @ Ser3 +# else + add \rb, \rb, #0x00010000 @ Ser1 +# endif + .endm + .macro writeb, rb + str \rb, [r3, #0x14] @ UTDR + .endm #else #error no serial architecture defined #endif @@ -151,22 +163,55 @@ ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} subs r0, r0, r1 @ calculate the delta offset - teq r0, #0 @ if delta is zero, we're + @ if delta is zero, we're beq not_relocated @ running at the address we @ were linked at. - add r2, r2, r0 @ different address, so we - add r3, r3, r0 @ need to fix up various - add r5, r5, r0 @ pointers. + /* + * We're running at a different address. We need to fix + * up various pointers: + * r5 - zImage base address + * r6 - GOT start + * ip - GOT end + */ + add r5, r5, r0 add r6, r6, r0 add ip, ip, r0 + +#ifndef CONFIG_ZBOOT_ROM + /* + * If we're running fully PIC === CONFIG_ZBOOT_ROM = n, + * we need to fix up pointers into the BSS region. + * r2 - BSS start + * r3 - BSS end + * sp - stack pointer + */ + add r2, r2, r0 + add r3, r3, r0 add sp, sp, r0 + /* + * Relocate all entries in the GOT table. + */ 1: ldr r1, [r6, #0] @ relocate entries in the GOT add r1, r1, r0 @ table. This fixes up the str r1, [r6], #4 @ C references. cmp r6, ip blo 1b +#else + + /* + * Relocate entries in the GOT table. We only relocate + * the entries that are outside the (relocated) BSS region. + */ +1: ldr r1, [r6, #0] @ relocate entries in the GOT + cmp r1, r2 @ entry < bss_start || + cmphs r3, r1 @ _end < entry + addlo r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b +#endif not_relocated: mov r0, #0 1: str r0, [r2], #4 @ clear bss @@ -176,6 +221,11 @@ cmp r2, r3 blo 1b + /* + * The C runtime environment should now be setup + * sufficiently. Turn the cache on, set up some + * pointers, and start decompressing. + */ bl cache_on mov r1, sp @ malloc space above stack diff -Nru a/arch/arm/boot/compressed/ll_char_wr.S b/arch/arm/boot/compressed/ll_char_wr.S --- a/arch/arm/boot/compressed/ll_char_wr.S Tue Oct 15 20:29:15 2002 +++ b/arch/arm/boot/compressed/ll_char_wr.S Tue Oct 15 20:29:15 2002 @@ -19,144 +19,116 @@ #include #include - .text + .text -#define BOLD 0x01 -#define ITALIC 0x02 -#define UNDERLINE 0x04 -#define FLASH 0x08 -#define INVERSE 0x10 - -LC0: .word bytes_per_char_h - .word video_size_row - .word acorndata_8x8 - .word con_charconvtable +LC0: .word LC0 + .word bytes_per_char_h + .word video_size_row + .word acorndata_8x8 + .word con_charconvtable +/* + * r0 = ptr + * r1 = char + * r2 = white + */ ENTRY(ll_write_char) - stmfd sp!, {r4 - r7, lr} + stmfd sp!, {r4 - r7, lr} @ @ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) @ - eor ip, r1, #UNDERLINE << 9 -/* - * calculate colours - */ - tst r1, #INVERSE << 9 - moveq r2, r1, lsr #16 - moveq r3, r1, lsr #24 - movne r2, r1, lsr #24 - movne r3, r1, lsr #16 - and r3, r3, #255 - and r2, r2, #255 -/* - * calculate offset into character table - */ - mov r1, r1, lsl #23 - mov r1, r1, lsr #20 -/* - * calculate offset required for each row [maybe I should make this an argument to this fn. - * Have to see what the register usage is like in the calling routines. - */ - adr r4, LC0 - ldmia r4, {r4, r5, r6, lr} - ldr r4, [r4] - ldr r5, [r5] -/* - * Go to resolution-dependent routine... - */ - cmp r4, #4 - blt Lrow1bpp - eor r2, r3, r2 @ Create eor mask to change colour from bg - orr r3, r3, r3, lsl #8 @ to fg. - orr r3, r3, r3, lsl #16 - add r0, r0, r5, lsl #3 @ Move to bottom of character - add r1, r1, #7 - ldrb r7, [r6, r1] - tst ip, #UNDERLINE << 9 - eoreq r7, r7, #255 - teq r4, #8 - beq Lrow8bpplp + /* + * calculate offset into character table + */ + mov r1, r1, lsl #3 + /* + * calculate offset required for each row. + */ + adr ip, LC0 + ldmia ip, {r3, r4, r5, r6, lr} + sub ip, ip, r3 + add r6, r6, ip + add lr, lr, ip + ldr r4, [r4, ip] + ldr r5, [r5, ip] + /* + * Go to resolution-dependent routine... + */ + cmp r4, #4 + blt Lrow1bpp + add r0, r0, r5, lsl #3 @ Move to bottom of character + orr r1, r1, #7 + ldrb r7, [r6, r1] + teq r4, #8 + beq Lrow8bpplp @ @ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) @ - orr r3, r3, r3, lsl #4 -Lrow4bpplp: ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - ldr r7, [lr, r7, lsl #2] - mul r7, r2, r7 - tst r1, #7 @ avoid using r7 directly after - eor ip, r3, r7 - str ip, [r0, -r5]! - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow4bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) +Lrow4bpplp: + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + sub r1, r1, #1 @ avoid using r7 directly after + str r7, [r0, -r5]! + ldrb r7, [r6, r1] + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + str r7, [r0, -r5]! + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow4bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) @ @ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) @ -Lrow8bpplp: mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r1, r1, #1 - ldrb r7, [r6, r1] - mov ip, r7, lsr #4 - ldr ip, [lr, ip, lsl #2] - mul r4, r2, ip - and ip, r7, #15 @ avoid r4 - ldr ip, [lr, ip, lsl #2] @ avoid r4 - mul ip, r2, ip @ avoid r4 - eor r4, r3, r4 @ avoid ip - tst r1, #7 @ avoid ip - sub r0, r0, r5 @ avoid ip - eor ip, r3, ip - stmia r0, {r4, ip} - subne r1, r1, #1 - ldrneb r7, [r6, r1] - bne Lrow8bpplp - LOADREGS(fd, sp!, {r4 - r7, pc}) +Lrow8bpplp: + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + sub r1, r1, #1 @ avoid ip + sub r0, r0, r5 @ avoid ip + stmia r0, {r4, ip} + ldrb r7, [r6, r1] + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + stmia r0, {r4, ip} + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow8bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) @ @ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) @ -Lrow1bpp: add r6, r6, r1 - ldmia r6, {r4, r7} - tst ip, #INVERSE << 9 - mvnne r4, r4 - mvnne r7, r7 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - mov r4, r4, lsr #8 - strb r4, [r0], r5 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - strb r7, [r0], r5 - mov r7, r7, lsr #8 - tst ip, #UNDERLINE << 9 - mvneq r7, r7 - strb r7, [r0], r5 - LOADREGS(fd, sp!, {r4 - r7, pc}) +Lrow1bpp: + add r6, r6, r1 + ldmia r6, {r4, r7} + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + LOADREGS(fd, sp!, {r4 - r7, pc}) - .bss + .bss ENTRY(con_charconvtable) - .space 1024 + .space 1024 diff -Nru a/arch/arm/config.in b/arch/arm/config.in --- a/arch/arm/config.in Tue Oct 15 20:29:12 2002 +++ b/arch/arm/config.in Tue Oct 15 20:29:12 2002 @@ -94,6 +94,8 @@ "$CONFIG_SA1100_XP860" = "y" ]; then define_bool CONFIG_SA1111 y define_int CONFIG_FORCE_MAX_ZONEORDER 9 +else + define_bool CONFIG_SA1111 n fi comment 'Processor Type' @@ -231,6 +233,8 @@ "$CONFIG_CPU_ARM922T" = "y" -o "$CONFIG_CPU_ARM926T" = "y" -o \ "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_XSCALE" = "y" ]; then dep_bool 'Support Thumb instructions (EXPERIMENTAL)' CONFIG_ARM_THUMB $CONFIG_EXPERIMENTAL +else + define_bool CONFIG_ARM_THUMB n fi if [ "$CONFIG_CPU_ARM920T" = "y" -o "$CONFIG_CPU_ARM922T" = "y" -o \ "$CONFIG_CPU_ARM926T" = "y" -o "$CONFIG_CPU_ARM1020" = "y" ]; then diff -Nru a/arch/arm/kernel/arch.c b/arch/arm/kernel/arch.c --- a/arch/arm/kernel/arch.c Tue Oct 15 20:29:12 2002 +++ b/arch/arm/kernel/arch.c Tue Oct 15 20:29:12 2002 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff -Nru a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c --- a/arch/arm/kernel/bios32.c Tue Oct 15 20:29:16 2002 +++ b/arch/arm/kernel/bios32.c Tue Oct 15 20:29:16 2002 @@ -599,7 +599,7 @@ * pcibios_enable_device - Enable I/O and memory. * @dev: PCI device to be enabled */ -int pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_device(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; int idx; @@ -608,6 +608,10 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for (idx = 0; idx < 6; idx++) { + /* Only set up the requested stuff */ + if (!(mask & (1 << idx))) + continue; + r = dev->resource + idx; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because" @@ -624,5 +628,31 @@ dev->slot_name, old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); } + return 0; +} + +int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine) +{ + struct pci_sys_data *root = dev->sysdata; + unsigned long prot, phys; + + if (mmap_state == pci_mmap_io) { + return -EINVAL; + } else { + phys = root->mem_offset + (vma->vm_pgoff << PAGE_SHIFT); + } + + /* + * Mark this as IO + */ + vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (remap_page_range(vma, vma->vm_start, phys, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + return 0; } diff -Nru a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c --- a/arch/arm/kernel/ecard.c Tue Oct 15 20:29:20 2002 +++ b/arch/arm/kernel/ecard.c Tue Oct 15 20:29:20 2002 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ #include #include #include +#include #ifndef CONFIG_ARCH_RPC #define HAVE_EXPMASK @@ -92,6 +94,8 @@ asmlinkage extern int ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); +static const struct ecard_id * +ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec); static inline unsigned short ecard_getu16(unsigned char *v) @@ -969,6 +973,14 @@ *ecp = ec; slot_to_expcard[slot] = ec; + + snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); + strcpy(ec->dev.name, "fixme!"); + ec->dev.parent = NULL; + ec->dev.bus = &ecard_bus_type; + + device_register(&ec->dev); + return 0; nodev: @@ -995,22 +1007,17 @@ if (finding_pos->claimed) continue; + if (finding_pos->dev.driver) + continue; + if (!cids) { if ((finding_pos->cid.id ^ cid) == 0) break; } else { - unsigned int manufacturer, product; - int i; - - manufacturer = finding_pos->cid.manufacturer; - product = finding_pos->cid.product; - - for (i = 0; cids[i].manufacturer != 65535; i++) - if (manufacturer == cids[i].manufacturer && - product == cids[i].product) - break; + const struct ecard_id *id; - if (cids[i].manufacturer != 65535) + id = ecard_match_device(cids, finding_pos); + if (id) break; } } @@ -1023,7 +1030,7 @@ * Locate all hardware - interrupt management and * actual cards. */ -void __init ecard_init(void) +static int __init ecard_init(void) { int slot, irqhw; @@ -1053,11 +1060,96 @@ irqhw ? ecard_irqexp_handler : ecard_irq_handler); ecard_proc_init(); + + return 0; } subsys_initcall(ecard_init); +/* + * ECARD "bus" + */ +static const struct ecard_id * +ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec) +{ + int i; + + for (i = 0; ids[i].manufacturer != 65535; i++) + if (ec->cid.manufacturer == ids[i].manufacturer && + ec->cid.product == ids[i].product) + return ids + i; + + return NULL; +} + +static int ecard_drv_probe(struct device *dev) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct ecard_driver *drv = ECARD_DRV(dev->driver); + const struct ecard_id *id; + + id = ecard_match_device(drv->id_table, ec); + + return drv->probe(ec, id); +} + +static int ecard_drv_remove(struct device *dev) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct ecard_driver *drv = ECARD_DRV(dev->driver); + + drv->remove(ec); + + return 0; +} + +int ecard_register_driver(struct ecard_driver *drv) +{ + drv->drv.bus = &ecard_bus_type; + drv->drv.probe = ecard_drv_probe; + drv->drv.remove = ecard_drv_remove; + + return driver_register(&drv->drv); +} + +void ecard_remove_driver(struct ecard_driver *drv) +{ + remove_driver(&drv->drv); +} + +static int ecard_match(struct device *_dev, struct device_driver *_drv) +{ + struct expansion_card *ec = ECARD_DEV(_dev); + struct ecard_driver *drv = ECARD_DRV(_drv); + int ret; + + if (drv->id_table) { + ret = ecard_match_device(drv->id_table, ec) != NULL; + } else { + ret = ec->cid.id == drv->id; + } + + return ret; +} + +struct bus_type ecard_bus_type = { + .name = "ecard", + .match = ecard_match, +}; + +static int ecard_bus_init(void) +{ + return bus_register(&ecard_bus_type); +} + +postcore_initcall(ecard_bus_init); + EXPORT_SYMBOL(ecard_startfind); EXPORT_SYMBOL(ecard_find); EXPORT_SYMBOL(ecard_readchunk); EXPORT_SYMBOL(ecard_address); + +EXPORT_SYMBOL(ecard_register_driver); +EXPORT_SYMBOL(ecard_remove_driver); + +EXPORT_SYMBOL(ecard_bus_type); diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S --- a/arch/arm/kernel/entry-armv.S Tue Oct 15 20:29:15 2002 +++ b/arch/arm/kernel/entry-armv.S Tue Oct 15 20:29:15 2002 @@ -189,11 +189,10 @@ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp mov r4, #0xe0000000 - orr r4, r4, #0x20 mov \irqstat, #0x0C - strb \irqstat, [r4] @outb(0x0C, 0x20) /* Poll command */ - ldrb \irqnr, [r4] @irq = inb(0x20) & 7 + strb \irqstat, [r4, #0x20] @outb(0x0C, 0x20) /* Poll command */ + ldrb \irqnr, [r4, #0x10] @irq = inb(0x20) & 7 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 43f @@ -201,8 +200,8 @@ teq \irqnr, #2 bne 44f 43: mov \irqstat, #0x0C - strb \irqstat, [r4, #0x80] @outb(0x0C, 0xA0) /* Poll command */ - ldrb \irqnr, [r4, #0x80] @irq = (inb(0xA0) & 7) + 8 + strb \irqstat, [r4, #0xa0] @outb(0x0C, 0xA0) /* Poll command */ + ldrb \irqnr, [r4, #0xa0] @irq = (inb(0xA0) & 7) + 8 and \irqstat, \irqnr, #0x80 teq \irqstat, #0 beq 44f @@ -655,7 +654,7 @@ and r2, r6, #31 @ int mode b bad_mode -#if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE +#if 1 /* defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE */ /* The FPE is always present */ .equ fpe_not_present, fpundefinstr #else @@ -766,6 +765,8 @@ msr spsr, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr + .ltorg + #ifdef CONFIG_PREEMPT svc_preempt: teq r9, #0 @ was preempt count = 0 ldreq r6, .LCirq_stat @@ -901,6 +902,8 @@ #endif mov why, #0 b ret_to_user + + .ltorg .align 5 __und_usr: sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c --- a/arch/arm/kernel/process.c Tue Oct 15 20:29:21 2002 +++ b/arch/arm/kernel/process.c Tue Oct 15 20:29:21 2002 @@ -367,8 +367,8 @@ dump->u_debugreg[0] = tsk->thread.debug.bp[0].address; dump->u_debugreg[1] = tsk->thread.debug.bp[1].address; - dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn; - dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn; + dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn.arm; + dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn.arm; dump->u_debugreg[4] = tsk->thread.debug.nsaved; if (dump->start_stack < 0x04000000) diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c --- a/arch/arm/kernel/ptrace.c Tue Oct 15 20:29:12 2002 +++ b/arch/arm/kernel/ptrace.c Tue Oct 15 20:29:12 2002 @@ -32,10 +32,24 @@ * in exit.c or in signal.c. */ +#if 1 /* * Breakpoint SWI instruction: SWI &9F0001 */ #define BREAKINST_ARM 0xef9f0001 +#define BREAKINST_THUMB 0xdf00 /* fill this in later */ +#else +/* + * New breakpoints - use an undefined instruction. The ARM architecture + * reference manual guarantees that the following instruction space + * will produce an undefined instruction exception on all CPUs: + * + * ARM: xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx + * Thumb: 1101 1110 xxxx xxxx + */ +#define BREAKINST_ARM 0xe7f001f0 +#define BREAKINST_THUMB 0xde01 +#endif /* * Get the address of the live pt_regs for the specified task. @@ -89,23 +103,32 @@ } static inline int -read_tsk_long(struct task_struct *child, unsigned long addr, unsigned long *res) +read_u32(struct task_struct *task, unsigned long addr, u32 *res) { - int copied; + int ret; - copied = access_process_vm(child, addr, res, sizeof(*res), 0); + ret = access_process_vm(task, addr, res, sizeof(*res), 0); - return copied != sizeof(*res) ? -EIO : 0; + return ret == sizeof(*res) ? 0 : -EIO; } static inline int -write_tsk_long(struct task_struct *child, unsigned long addr, unsigned long val) +read_instr(struct task_struct *task, unsigned long addr, u32 *res) { - int copied; - - copied = access_process_vm(child, addr, &val, sizeof(val), 1); + int ret; - return copied != sizeof(val) ? -EIO : 0; + if (addr & 1) { + u16 val; + ret = access_process_vm(task, addr & ~1, &val, sizeof(val), 0); + ret = ret == sizeof(val) ? 0 : -EIO; + *res = val; + } else { + u32 val; + ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); + ret = ret == sizeof(val) ? 0 : -EIO; + *res = val; + } + return ret; } /* @@ -206,7 +229,7 @@ static unsigned long get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) { - unsigned long alt = 0; + u32 alt = 0; switch (insn & 0x0e000000) { case 0x00000000: @@ -262,7 +285,7 @@ else base -= aluop2; } - if (read_tsk_long(child, base, &alt) == 0) + if (read_u32(child, base, &alt) == 0) alt = pc_pointer(alt); } break; @@ -289,7 +312,7 @@ base = ptrace_getrn(child, insn); - if (read_tsk_long(child, base + nr_regs, &alt) == 0) + if (read_u32(child, base + nr_regs, &alt) == 0) alt = pc_pointer(alt); break; } @@ -319,30 +342,71 @@ } static int -add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr) +swap_insn(struct task_struct *task, unsigned long addr, + void *old_insn, void *new_insn, int size) +{ + int ret; + + ret = access_process_vm(task, addr, old_insn, size, 0); + if (ret == size) + ret = access_process_vm(task, addr, new_insn, size, 1); + return ret; +} + +static void +add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) { int nr = dbg->nsaved; - int res = -EINVAL; if (nr < 2) { - res = read_tsk_long(child, addr, &dbg->bp[nr].insn); - if (res == 0) - res = write_tsk_long(child, addr, BREAKINST_ARM); + u32 new_insn = BREAKINST_ARM; + int res; + + res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); - if (res == 0) { + if (res == 4) { dbg->bp[nr].address = addr; dbg->nsaved += 1; } } else printk(KERN_ERR "ptrace: too many breakpoints\n"); +} - return res; +/* + * Clear one breakpoint in the user program. We copy what the hardware + * does and use bit 0 of the address to indicate whether this is a Thumb + * breakpoint or an ARM breakpoint. + */ +static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) +{ + unsigned long addr = bp->address; + union debug_insn old_insn; + int ret; + + if (addr & 1) { + ret = swap_insn(task, addr & ~1, &old_insn.thumb, + &bp->insn.thumb, 2); + + if (ret != 2 || old_insn.thumb != BREAKINST_THUMB) + printk(KERN_ERR "%s:%d: corrupted Thumb breakpoint at " + "0x%08lx (0x%04x)\n", task->comm, task->pid, + addr, old_insn.thumb); + } else { + ret = swap_insn(task, addr & ~3, &old_insn.arm, + &bp->insn.arm, 4); + + if (ret != 4 || old_insn.arm != BREAKINST_ARM) + printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " + "0x%08lx (0x%08x)\n", task->comm, task->pid, + addr, old_insn.arm); + } } void ptrace_set_bpt(struct task_struct *child) { struct pt_regs *regs; - unsigned long pc, insn; + unsigned long pc; + u32 insn; int res; regs = get_user_regs(child); @@ -353,7 +417,7 @@ return; } - res = read_tsk_long(child, pc, &insn); + res = read_instr(child, pc, &insn); if (!res) { struct debug_info *dbg = &child->thread.debug; unsigned long alt; @@ -362,7 +426,7 @@ alt = get_branch_address(child, pc, insn); if (alt) - res = add_breakpoint(child, dbg, alt); + add_breakpoint(child, dbg, alt); /* * Note that we ignore the result of setting the above @@ -374,7 +438,7 @@ * loose control of the thread during single stepping. */ if (!alt || predicate(insn) != PREDICATE_ALWAYS) - res = add_breakpoint(child, dbg, pc + 4); + add_breakpoint(child, dbg, pc + 4); } } @@ -384,24 +448,17 @@ */ void __ptrace_cancel_bpt(struct task_struct *child) { - struct debug_info *dbg = &child->thread.debug; - int i, nsaved = dbg->nsaved; + int i, nsaved = child->thread.debug.nsaved; - dbg->nsaved = 0; + child->thread.debug.nsaved = 0; if (nsaved > 2) { printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); nsaved = 2; } - for (i = 0; i < nsaved; i++) { - unsigned long tmp; - - read_tsk_long(child, dbg->bp[i].address, &tmp); - write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn); - if (tmp != BREAKINST_ARM) - printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n"); - } + for (i = 0; i < nsaved; i++) + clear_breakpoint(child, &child->thread.debug.bp[i]); } /* @@ -537,9 +594,12 @@ */ case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: - ret = read_tsk_long(child, addr, &tmp); - if (!ret) + ret = access_process_vm(child, addr, &tmp, + sizeof(unsigned long), 0); + if (ret == sizeof(unsigned long)) ret = put_user(tmp, (unsigned long *) data); + else + ret = -EIO; break; case PTRACE_PEEKUSR: @@ -551,7 +611,12 @@ */ case PTRACE_POKETEXT: case PTRACE_POKEDATA: - ret = write_tsk_long(child, addr, data); + ret = access_process_vm(child, addr, &data, + sizeof(unsigned long), 1); + if (ret == sizeof(unsigned long)) + ret = 0; + else + ret = -EIO; break; case PTRACE_POKEUSR: diff -Nru a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c --- a/arch/arm/kernel/setup.c Tue Oct 15 20:29:17 2002 +++ b/arch/arm/kernel/setup.c Tue Oct 15 20:29:17 2002 @@ -193,26 +193,25 @@ CACHE_LINE(cache))); } -static inline void dump_cpu_cache_id(void) +static void __init dump_cpu_info(void) { - unsigned int cache_info; + unsigned int info; - asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info)); + asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (info)); - if (cache_info == processor_id) - return; - - printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]); - if (CACHE_S(cache_info)) { - dump_cache("CPU: I cache", CACHE_ISIZE(cache_info)); - dump_cache("CPU: D cache", CACHE_DSIZE(cache_info)); - } else { - dump_cache("CPU: cache", CACHE_ISIZE(cache_info)); + if (info != processor_id) { + printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(info)]); + if (CACHE_S(info)) { + dump_cache("CPU: I cache", CACHE_ISIZE(info)); + dump_cache("CPU: D cache", CACHE_DSIZE(info)); + } else { + dump_cache("CPU: cache", CACHE_ISIZE(info)); + } } } #else -#define dump_cpu_cache_id() do { } while (0) +#define dump_cpu_info() do { } while (0) #endif static void __init setup_processor(void) @@ -255,7 +254,7 @@ proc_info.manufacturer, proc_info.cpu_name, (int)processor_id & 15); - dump_cpu_cache_id(); + dump_cpu_info(); sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); diff -Nru a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c --- a/arch/arm/kernel/signal.c Tue Oct 15 20:29:11 2002 +++ b/arch/arm/kernel/signal.c Tue Oct 15 20:29:11 2002 @@ -59,11 +59,11 @@ sigset_t saveset; mask &= _BLOCKABLE; - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); regs->ARM_r0 = -EINTR; while (1) { @@ -87,11 +87,11 @@ return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); regs->ARM_r0 = -EINTR; while (1) { @@ -207,10 +207,10 @@ goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); if (restore_sigcontext(regs, &frame->sc)) goto badframe; @@ -247,10 +247,10 @@ goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -477,12 +477,12 @@ ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(&tsk->sigmask_lock); + spin_lock_irq(&tsk->sig->siglock); sigorsets(&tsk->blocked, &tsk->blocked, &ka->sa.sa_mask); sigaddset(&tsk->blocked, sig); recalc_sigpending(); - spin_unlock_irq(&tsk->sigmask_lock); + spin_unlock_irq(&tsk->sig->siglock); } return; } @@ -520,20 +520,10 @@ for (;;) { unsigned long signr = 0; struct k_sigaction *ka; - sigset_t *mask = ¤t->blocked; - local_irq_disable(); - if (current->sig->shared_pending.head) { - spin_lock(¤t->sig->siglock); - signr = dequeue_signal(¤t->sig->shared_pending, mask, &info); - spin_unlock(¤t->sig->siglock); - } - if (!signr) { - spin_lock(¤t->sigmask_lock); - signr = dequeue_signal(¤t->pending, mask, &info); - spin_unlock(¤t->sigmask_lock); - } - local_irq_enable(); + spin_lock_irq(¤t->sig->siglock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sig->siglock); if (!signr) break; diff -Nru a/arch/arm/kernel/time-acorn.c b/arch/arm/kernel/time-acorn.c --- a/arch/arm/kernel/time-acorn.c Tue Oct 15 20:29:23 2002 +++ b/arch/arm/kernel/time-acorn.c Tue Oct 15 20:29:23 2002 @@ -25,44 +25,37 @@ static unsigned long ioctime_gettimeoffset(void) { - unsigned int count1, count2, status1, status2; - unsigned long offset = 0; + unsigned int count1, count2, status; + long offset; - status1 = ioc_readb(IOC_IRQREQA); - barrier (); ioc_writeb (0, IOC_T0LATCH); barrier (); count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); barrier (); - status2 = ioc_readb(IOC_IRQREQA); + status = ioc_readb(IOC_IRQREQA); barrier (); ioc_writeb (0, IOC_T0LATCH); barrier (); count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + offset = count2; if (count2 < count1) { /* - * This means that we haven't just had an interrupt - * while reading into status2. + * We have not had an interrupt between reading count1 + * and count2. */ - if (status2 & (1 << 5)) - offset = tick; - count1 = count2; + if (status & (1 << 5)) + offset -= LATCH; } else if (count2 > count1) { /* - * We have just had another interrupt while reading - * status2. + * We have just had another interrupt between reading + * count1 and count2. */ - offset += tick; - count1 = count2; + offset -= LATCH; } - count1 = LATCH - count1; - /* - * count1 = number of clock ticks since last interrupt - */ - offset += count1 * tick / LATCH; - return offset; + offset = (LATCH - offset) * (tick_nsec / 1000); + return (offset + LATCH/2) / LATCH; } void __init ioctime_init(void) diff -Nru a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c --- a/arch/arm/kernel/time.c Tue Oct 15 20:29:19 2002 +++ b/arch/arm/kernel/time.c Tue Oct 15 20:29:19 2002 @@ -115,8 +115,8 @@ time_before(xtime.tv_sec, next_rtc_update)) return; - if (xtime.tv_usec < 50000 - (tick >> 1) && - xtime.tv_usec >= 50000 + (tick >> 1)) + if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) && + xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1)) return; if (set_rtc()) @@ -166,7 +166,7 @@ usec += lost * USECS_PER_JIFFY; sec = xtime.tv_sec; - usec += xtime.tv_usec; + usec += xtime.tv_nsec / 1000; read_unlock_irqrestore(&xtime_lock, flags); /* usec may have gone up a lot: be safe */ @@ -196,7 +196,8 @@ tv->tv_sec--; } - xtime = *tv; + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = tv->tv_usec * 1000; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c --- a/arch/arm/kernel/traps.c Tue Oct 15 20:29:16 2002 +++ b/arch/arm/kernel/traps.c Tue Oct 15 20:29:16 2002 @@ -32,6 +32,7 @@ #include #include #include +#include #include "ptrace.h" @@ -77,8 +78,7 @@ fs = get_fs(); set_fs(KERNEL_DS); - printk("%s", str); - printk("(0x%08lx to 0x%08lx)\n", bottom, top); + printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); for (p = bottom & ~31; p < top;) { printk("%04lx: ", p & 0xffff); @@ -136,7 +136,7 @@ set_fs(fs); } -static void dump_stack(struct task_struct *tsk, unsigned long sp) +static void __dump_stack(struct task_struct *tsk, unsigned long sp) { dump_mem("Stack: ", sp, 8192+(unsigned long)tsk->thread_info); } @@ -163,15 +163,20 @@ } /* - * This is called from SysRq-T (show_task) to display the current - * call trace for each process. Very useful. + * This is called from SysRq-T (show_task) to display the current call + * trace for each process. This version will also display the running + * threads call trace (ie, us.) */ void show_trace_task(struct task_struct *tsk) { - if (tsk != current) { - unsigned int fp = thread_saved_fp(tsk); - c_backtrace(fp, 0x10); - } + unsigned int fp; + + if (tsk != current) + fp = thread_saved_fp(tsk); + else + asm("mov%? %0, fp" : "=r" (fp)); + + c_backtrace(fp, 0x10); } spinlock_t die_lock = SPIN_LOCK_UNLOCKED; @@ -193,7 +198,7 @@ current->comm, current->pid, tsk->thread_info + 1); if (!user_mode(regs) || in_interrupt()) { - dump_stack(tsk, (unsigned long)(regs + 1)); + __dump_stack(tsk, (unsigned long)(regs + 1)); dump_backtrace(regs, tsk); dump_instr(regs); } diff -Nru a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c --- a/arch/arm/mach-integrator/cpu.c Tue Oct 15 20:29:17 2002 +++ b/arch/arm/mach-integrator/cpu.c Tue Oct 15 20:29:17 2002 @@ -73,36 +73,37 @@ * Validate the speed in khz. If it is outside our * range, then return the lowest. */ -static unsigned int -integrator_validatespeed(unsigned int cpu, unsigned int freq_khz) +static void integrator_verify_speed(struct cpufreq_policy *policy) { struct vco vco; - if (freq_khz < 12000) - freq_khz = 12000; - if (freq_khz > 160000) - freq_khz = 160000; + if (policy->max > policy->max_cpu_freq) + policy->max = policy->max_cpu_freq; - vco = freq_to_vco(freq_khz, 1); + if (policy->max < 12000) + policy->max = 12000; + if (policy->max > 160000) + policy->max = 160000; + + vco = freq_to_vco(policy->max, 1); + + if (vco.vdw < 4) + vco.vdw = 4; + if (vco.vdw > 152) + vco.vdw = 152; - if (vco.vdw < 4 || vco.vdw > 152) - return -EINVAL; - - return vco_to_freq(vco, 1); + policy->min = policy->max = vco_to_freq(vco, 1); } -static void integrator_setspeed(unsigned int cpu, unsigned int freq_khz) +static void do_set_policy(int cpu, struct cpufreq_policy *policy) { - struct vco vco = freq_to_vco(freq_khz, 1); - unsigned long cpus_allowed; + struct vco vco = freq_to_vco(policy->max, 1); u_int cm_osc; /* - * Save this threads cpus_allowed mask, and bind to the - * specified CPU. When this call returns, we should be - * running on the right CPU. + * Bind to the specified CPU. When this call returns, + * we should be running on the right CPU. */ - cpus_allowed = current->cpus_allowed; set_cpus_allowed(current, 1 << cpu); BUG_ON(cpu != smp_processor_id()); @@ -113,6 +114,26 @@ __raw_writel(0xa05f, CM_LOCK); __raw_writel(cm_osc, CM_OSC); __raw_writel(0, CM_LOCK); +} + +static void integrator_set_policy(struct cpufreq_policy *policy) +{ + unsigned long cpus_allowed; + int cpu; + + /* + * Save this threads cpus_allowed mask. + */ + cpus_allowed = current->cpus_allowed; + + if (policy->cpu == CPUFREQ_ALL_CPUS) { + for (cpu = 0; cpu < NR_CPUS; cpu++) { + if (!cpu_online(cpu)) + continue; + do_set_policy(cpu, policy); + } + } else + do_set_policy(policy->cpu, policy); /* * Restore the CPUs allowed mask. @@ -120,23 +141,30 @@ set_cpus_allowed(current, cpus_allowed); } +static struct cpufreq_policy integrator_policy = { + .cpu = 0, + .policy = CPUFREQ_POLICY_POWERSAVE, + .max_cpu_freq = 160000, +}; + static struct cpufreq_driver integrator_driver = { - .validate = integrator_validatespeed, - .setspeed = integrator_setspeed, - .sync = 1, + .verify = integrator_verify_speed, + .setpolicy = integrator_set_policy, + .policy = &integrator_policy, + .cpu_min_freq = 12000, }; #endif static int __init integrator_cpu_init(void) { - struct cpufreq_freqs *freqs; + struct cpufreq_policy *policies; unsigned long cpus_allowed; int cpu; - freqs = kmalloc(sizeof(struct cpufreq_freqs) * NR_CPUS, - GFP_KERNEL); - if (!freqs) { - printk(KERN_ERR "CPU: unable to allocate cpufreqs structure\n"); + policies = kmalloc(sizeof(struct cpufreq_freqs) * NR_CPUS, + GFP_KERNEL); + if (!policies) { + printk(KERN_ERR "CPU: unable to allocate policies structure\n"); return -ENOMEM; } @@ -164,18 +192,20 @@ vco.od = (cm_osc >> 8) & 7; vco.vdw = cm_osc & 255; - freqs[cpu].min = 12000; - freqs[cpu].max = 160000; - freqs[cpu].cur = vco_to_freq(vco, 1); + policies[cpu].cpu = cpu; + policies[cpu].policy = CPUFREQ_POLICY_POWERSAVE, + policies[cpu].max_cpu_freq = 160000; + policies[cpu].min = + policies[cpu].max = vco_to_freq(vco, 1); } set_cpus_allowed(current, cpus_allowed); #ifdef CONFIG_CPU_FREQ - integrator_driver.freq = freqs; + integrator_driver.policy = policies; cpufreq_register(&integrator_driver); #else - kfree(freqs); + kfree(policies); #endif return 0; diff -Nru a/arch/arm/mach-iop310/iop310-pci.c b/arch/arm/mach-iop310/iop310-pci.c --- a/arch/arm/mach-iop310/iop310-pci.c Tue Oct 15 20:29:16 2002 +++ b/arch/arm/mach-iop310/iop310-pci.c Tue Oct 15 20:29:16 2002 @@ -145,7 +145,7 @@ } static int -iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where +iop310_pri_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { unsigned long addr = iop310_cfg_address(bus, devfn, where); @@ -163,7 +163,7 @@ else val &= ~(0xffff << where); - *IOP310_POCCDR = val | v << where; + *IOP310_POCCDR = val | value << where; } else { asm volatile( "str %1, [%2]\n\t" @@ -173,7 +173,7 @@ "nop\n\t" "nop\n\t" : - : "r" (val), "r" (addr), + : "r" (value), "r" (addr), "r" (IOP310_POCCAR), "r" (IOP310_POCCDR)); } @@ -246,7 +246,7 @@ } static int -iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where +iop310_sec_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { unsigned long addr = iop310_cfg_address(bus, devfn, where); @@ -265,7 +265,7 @@ else val &= ~(0xffff << where); - *IOP310_SOCCDR = val | v << where; + *IOP310_SOCCDR = val | value << where; } else { asm volatile( "str %1, [%2]\n\t" @@ -275,7 +275,7 @@ "nop\n\t" "nop\n\t" : - : "r" (val), "r" (addr), + : "r" (value), "r" (addr), "r" (IOP310_SOCCAR), "r" (IOP310_SOCCDR)); } diff -Nru a/arch/arm/mach-iop310/iq80310-time.c b/arch/arm/mach-iop310/iq80310-time.c --- a/arch/arm/mach-iop310/iq80310-time.c Tue Oct 15 20:29:19 2002 +++ b/arch/arm/mach-iop310/iq80310-time.c Tue Oct 15 20:29:19 2002 @@ -85,7 +85,7 @@ /* * Now convert them to usec. */ - usec = (unsigned long)(elapsed*tick)/LATCH; + usec = (unsigned long)(elapsed * (tick_nsec / 1000))/LATCH; return usec; } diff -Nru a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile --- a/arch/arm/mach-sa1100/Makefile Tue Oct 15 20:29:23 2002 +++ b/arch/arm/mach-sa1100/Makefile Tue Oct 15 20:29:23 2002 @@ -2,20 +2,17 @@ # Makefile for the linux kernel. # -# Common support (must be linked before board specific support) +# Common support obj-y := generic.o irq.o dma.o obj-m := obj-n := obj- := led-y := leds.o -export-objs := dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o \ - usb_ctl.o usb_recv.o usb_send.o +export-objs := dma.o generic.o pcipool.o pm.o sa1111.o sa1111-pcibuf.o # This needs to be cleaned up. We probably need to have SA1100 # and SA1110 config symbols. -# -# We link the CPU support next, so that RAM timings can be tuned. ifeq ($(CONFIG_CPU_FREQ),y) obj-$(CONFIG_SA1100_ASSABET) += cpu-sa1110.o obj-$(CONFIG_SA1100_CERF) += cpu-sa1110.o @@ -107,10 +104,7 @@ obj-$(CONFIG_LEDS) += $(led-y) # SA1110 USB client support -sa1100usb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o -obj-$(CONFIG_SA1100_USB) += sa1100usb_core.o -obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o -obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o +#obj-$(CONFIG_SA1100_USB) += usb/ # Miscelaneous functions obj-$(CONFIG_PM) += pm.o sleep.o diff -Nru a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c --- a/arch/arm/mach-sa1100/assabet.c Tue Oct 15 20:29:11 2002 +++ b/arch/arm/mach-sa1100/assabet.c Tue Oct 15 20:29:11 2002 @@ -302,21 +302,24 @@ */ neponset_map_io(); #endif - /* - * When Neponset is attached, the first UART should be - * UART3. That's what Angel is doing and many documents - * are stating this. - * We do the Neponset mapping even if Neponset support - * isn't compiled in so the user will still get something on - * the expected physical serial port. - */ - sa1100_register_uart(0, 3); - sa1100_register_uart(2, 1); } else { sa1100_register_uart_fns(&assabet_port_fns); - sa1100_register_uart(0, 1); /* com port */ - sa1100_register_uart(2, 3); /* radio module */ } + + /* + * When Neponset is attached, the first UART should be + * UART3. That's what Angel is doing and many documents + * are stating this. + * + * We do the Neponset mapping even if Neponset support + * isn't compiled in so the user will still get something on + * the expected physical serial port. + * + * We no longer do this; not all boot loaders support it, + * and UART3 appears to be somewhat unreliable with blob. + */ + sa1100_register_uart(0, 1); + sa1100_register_uart(2, 3); } diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c --- a/arch/arm/mach-sa1100/generic.c Tue Oct 15 20:29:15 2002 +++ b/arch/arm/mach-sa1100/generic.c Tue Oct 15 20:29:15 2002 @@ -55,8 +55,8 @@ khz /= 100; - for (i = 0; i < ARRAY_SIZE(cclk_frequency_100khz); i--) - if (cclk_frequency_100khz[i] >= khz) + for (i = NR_FREQS - 1; i > 0; i--) + if (cclk_frequency_100khz[i] <= khz) break; return i; diff -Nru a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c --- a/arch/arm/mach-sa1100/neponset.c Tue Oct 15 20:29:17 2002 +++ b/arch/arm/mach-sa1100/neponset.c Tue Oct 15 20:29:17 2002 @@ -193,20 +193,30 @@ } static struct device_driver neponset_device_driver = { - .suspend = neponset_suspend, - .resume = neponset_resume, + .name = "NEPONSET", + .bus = &system_bus_type, + .suspend = neponset_suspend, + .resume = neponset_resume, }; -static struct device neponset_device = { - .name = "Neponset", - .bus_id = "neponset", - .driver = &neponset_device_driver, +static struct sys_device neponset_device = { + .name = "NEPONSET", + .id = 0, + .root = NULL, + .dev = { + .name = "Neponset", + .bus_id = "neponset", + .bus = &system_bus_type, + .driver = &neponset_device_driver, + }, }; static int __init neponset_init(void) { int ret; + driver_register(&neponset_device_driver); + /* * The Neponset is only present on the Assabet machine type. */ @@ -231,7 +241,7 @@ return -ENODEV; } - ret = register_sys_device(&neponset_device); + ret = sys_device_register(&neponset_device); if (ret) return ret; @@ -256,7 +266,7 @@ return sa1111_init(0x40000000, IRQ_NEPONSET_SA1111); } -arch_initcall(neponset_init); +subsys_initcall(neponset_init); static struct map_desc neponset_io_desc[] __initdata = { /* virtual physical length type */ diff -Nru a/arch/arm/mach-sa1100/sa1111.c b/arch/arm/mach-sa1100/sa1111.c --- a/arch/arm/mach-sa1100/sa1111.c Tue Oct 15 20:29:16 2002 +++ b/arch/arm/mach-sa1100/sa1111.c Tue Oct 15 20:29:16 2002 @@ -43,7 +43,7 @@ * anchor point for all the other drivers. */ struct sa1111 { - struct device dev; + struct device *dev; struct resource res; int irq; spinlock_t lock; @@ -64,7 +64,7 @@ .devid = SA1111_DEVID_USB, .irq = { IRQ_USBPWR, - IRQ_NHCIM, + IRQ_HCIM, IRQ_HCIBUFFACC, IRQ_HCIRMTWKP, IRQ_NHCIMFCIR, @@ -148,7 +148,6 @@ &ssp_dev, &kbd_dev, &mse_dev, - &int_dev, &pcmcia_dev, }; @@ -158,7 +157,6 @@ 0x0800, SA1111_KBD, SA1111_MSE, - SA1111_INTC, 0x1800, }; @@ -372,7 +370,106 @@ set_irq_chained_handler(sadev->irq[0], sa1111_irq_handler); } -static struct device_driver sa1111_device_driver; +/* + * Bring the SA1111 out of reset. This requires a set procedure: + * 1. nRESET asserted (by hardware) + * 2. CLK turned on from SA1110 + * 3. nRESET deasserted + * 4. VCO turned on, PLL_BYPASS turned off + * 5. Wait lock time, then assert RCLKEn + * 7. PCR set to allow clocking of individual functions + * + * Until we've done this, the only registers we can access are: + * SBI_SKCR + * SBI_SMCR + * SBI_SKID + */ +static void sa1111_wake(struct sa1111 *sachip) +{ + unsigned long flags, r; + + spin_lock_irqsave(&sachip->lock, flags); + + /* + * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: + * (SA-1110 Developer's Manual, section 9.1.2.1) + */ + GAFR |= GPIO_32_768kHz; + GPDR |= GPIO_32_768kHz; + TUCR = TUCR_3_6864MHz; + + /* + * Turn VCO on, and disable PLL Bypass. + */ + r = sa1111_readl(sachip->base + SA1111_SKCR); + r &= ~SKCR_VCO_OFF; + sa1111_writel(r, sachip->base + SA1111_SKCR); + r |= SKCR_PLL_BYPASS | SKCR_OE_EN; + sa1111_writel(r, sachip->base + SA1111_SKCR); + + /* + * Wait lock time. SA1111 manual _doesn't_ + * specify a figure for this! We choose 100us. + */ + udelay(100); + + /* + * Enable RCLK. We also ensure that RDYEN is set. + */ + r |= SKCR_RCLKEN | SKCR_RDYEN; + sa1111_writel(r, sachip->base + SA1111_SKCR); + + /* + * Wait 14 RCLK cycles for the chip to finish coming out + * of reset. (RCLK=24MHz). This is 590ns. + */ + udelay(1); + + /* + * Ensure all clocks are initially off. + */ + sa1111_writel(0, sachip->base + SA1111_SKPCR); + + spin_unlock_irqrestore(&sachip->lock, flags); +} + +/* + * Configure the SA1111 shared memory controller. + */ +void +sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, + unsigned int cas_latency) +{ + unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); + + if (cas_latency == 3) + smcr |= SMCR_CLAT; + + sa1111_writel(smcr, sachip->base + SA1111_SMCR); +} + +static void +sa1111_init_one_child(struct sa1111 *sachip, struct sa1111_dev *sadev, unsigned int offset) +{ + snprintf(sadev->dev.bus_id, sizeof(sadev->dev.bus_id), + "%4.4x", offset); + + sadev->dev.parent = sachip->dev; + sadev->dev.bus = &sa1111_bus_type; + sadev->res.start = sachip->res.start + offset; + sadev->res.end = sadev->res.start + 511; + sadev->res.name = sadev->dev.name; + sadev->res.flags = IORESOURCE_MEM; + sadev->mapbase = sachip->base + offset; + + if (request_resource(&sachip->res, &sadev->res)) { + printk("SA1111: failed to allocate resource for %s\n", + sadev->res.name); + return; + } + + device_register(&sadev->dev); +} /** * sa1111_probe - probe for a single SA1111 chip. @@ -387,11 +484,11 @@ * %0 successful. */ static int __init -sa1111_probe(unsigned long phys_addr, int irq) +__sa1111_probe(struct device *me, unsigned long phys_addr, int irq) { struct sa1111 *sachip; unsigned long id; - unsigned int has_devs; + unsigned int has_devs, val; int i, ret = -ENODEV; sachip = kmalloc(sizeof(struct sa1111), GFP_KERNEL); @@ -402,12 +499,10 @@ spin_lock_init(&sachip->lock); - strncpy(sachip->dev.name, "Intel Corporation SA1111", sizeof(sachip->dev.name)); - snprintf(sachip->dev.bus_id, sizeof(sachip->dev.bus_id), "%8.8lx", phys_addr); - sachip->dev.driver = &sa1111_device_driver; - sachip->dev.driver_data = sachip; + sachip->dev = me; + dev_set_drvdata(sachip->dev, sachip); - sachip->res.name = sachip->dev.name; + sachip->res.name = me->name; sachip->res.start = phys_addr; sachip->res.end = phys_addr + 0x2000; sachip->irq = irq; @@ -417,6 +512,10 @@ goto out; } + /* + * Map the whole region. This also maps the + * registers for our children. + */ sachip->base = ioremap(phys_addr, PAGE_SIZE * 2); if (!sachip->base) { ret = -ENOMEM; @@ -433,17 +532,47 @@ goto unmap; } - /* - * We found the chip. - */ - ret = register_sys_device(&sachip->dev); - if (ret) - printk("sa1111 device_register failed: %d\n", ret); - printk(KERN_INFO "SA1111 Microprocessor Companion Chip: " "silicon revision %lx, metal revision %lx\n", (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); + /* + * We found it. Wake the chip up, and initialise. + */ + sa1111_wake(sachip); + + /* + * The SDRAM configuration of the SA1110 and the SA1111 must + * match. This is very important to ensure that SA1111 accesses + * don't corrupt the SDRAM. Note that this ungates the SA1111's + * MBGNT signal, so we must have called sa1110_mb_disable() + * beforehand. + */ + sa1111_configure_smc(sachip, 1, + FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), + FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); + + /* + * We only need to turn on DCLK whenever we want to use the + * DMA. It can otherwise be held firmly in the off position. + * (currently, we always enable it.) + */ + val = sa1111_readl(sachip->base + SA1111_SKPCR); + sa1111_writel(val | SKPCR_DCLKEN, sachip->base + SA1111_SKPCR); + + /* + * Enable the SA1110 memory bus request and grant signals. + */ + sa1110_mb_enable(); + + /* + * The interrupt controller must be initialised before any + * other device to ensure that the interrupts are available. + */ + int_dev.irq[0] = irq; + sa1111_init_one_child(sachip, &int_dev, SA1111_INTC); + sa1111_init_irq(&int_dev); + g_sa1111 = sachip; has_devs = ~0; @@ -453,29 +582,9 @@ else has_devs &= ~(1 << 1); - for (i = 0; i < ARRAY_SIZE(devs); i++) { - if (!(has_devs & (1 << i))) - continue; - - snprintf(devs[i]->dev.bus_id, sizeof(devs[i]->dev.bus_id), - "%4.4x", dev_offset[i]); - - devs[i]->dev.parent = &sachip->dev; - devs[i]->dev.bus = &sa1111_bus_type; - devs[i]->res.start = sachip->res.start + dev_offset[i]; - devs[i]->res.end = devs[i]->res.start + 511; - devs[i]->res.name = devs[i]->dev.name; - devs[i]->res.flags = IORESOURCE_MEM; - devs[i]->mapbase = sachip->base + dev_offset[i]; - - if (request_resource(&sachip->res, &devs[i]->res)) { - printk("SA1111: failed to allocate resource for %s\n", - devs[i]->res.name); - continue; - } - - device_register(&devs[i]->dev); - } + for (i = 0; i < ARRAY_SIZE(devs); i++) + if (has_devs & (1 << i)) + sa1111_init_one_child(sachip, devs[i], dev_offset[i]); return 0; @@ -503,84 +612,6 @@ } /* - * Bring the SA1111 out of reset. This requires a set procedure: - * 1. nRESET asserted (by hardware) - * 2. CLK turned on from SA1110 - * 3. nRESET deasserted - * 4. VCO turned on, PLL_BYPASS turned off - * 5. Wait lock time, then assert RCLKEn - * 7. PCR set to allow clocking of individual functions - * - * Until we've done this, the only registers we can access are: - * SBI_SKCR - * SBI_SMCR - * SBI_SKID - */ -static void sa1111_wake(struct sa1111 *sachip) -{ - unsigned long flags, r; - - spin_lock_irqsave(&sachip->lock, flags); - - /* - * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111: - * (SA-1110 Developer's Manual, section 9.1.2.1) - */ - GAFR |= GPIO_32_768kHz; - GPDR |= GPIO_32_768kHz; - TUCR = TUCR_3_6864MHz; - - /* - * Turn VCO on, and disable PLL Bypass. - */ - r = sa1111_readl(sachip->base + SA1111_SKCR); - r &= ~SKCR_VCO_OFF; - sa1111_writel(r, sachip->base + SA1111_SKCR); - r |= SKCR_PLL_BYPASS | SKCR_OE_EN; - sa1111_writel(r, sachip->base + SA1111_SKCR); - - /* - * Wait lock time. SA1111 manual _doesn't_ - * specify a figure for this! We choose 100us. - */ - udelay(100); - - /* - * Enable RCLK. We also ensure that RDYEN is set. - */ - r |= SKCR_RCLKEN | SKCR_RDYEN; - sa1111_writel(r, sachip->base + SA1111_SKCR); - - /* - * Wait 14 RCLK cycles for the chip to finish coming out - * of reset. (RCLK=24MHz). This is 590ns. - */ - udelay(1); - - /* - * Ensure all clocks are initially off. - */ - sa1111_writel(0, sachip->base + SA1111_SKPCR); - - spin_unlock_irqrestore(&sachip->lock, flags); -} - -/* - * Configure the SA1111 shared memory controller. - */ -void -sa1111_configure_smc(struct sa1111 *sachip, int sdram, unsigned int drac, - unsigned int cas_latency) -{ - unsigned int smcr = SMCR_DTIM | SMCR_MBGE | FInsrt(drac, SMCR_DRAC); - - if (cas_latency == 3) - smcr |= SMCR_CLAT; - - sa1111_writel(smcr, sachip->base + SA1111_SMCR); -} - -/* * According to the "Intel StrongARM SA-1111 Microprocessor Companion * Chip Specification Update" (June 2000), erratum #7, there is a * significant bug in the SA1111 SDRAM shared memory controller. If @@ -648,52 +679,6 @@ return 0; } -int sa1111_init(unsigned long phys, unsigned int irq) -{ - unsigned int val; - int ret; - - ret = sa1111_probe(phys, irq); - if (ret < 0) - return ret; - - /* - * We found it. Wake the chip up. - */ - sa1111_wake(g_sa1111); - - /* - * The SDRAM configuration of the SA1110 and the SA1111 must - * match. This is very important to ensure that SA1111 accesses - * don't corrupt the SDRAM. Note that this ungates the SA1111's - * MBGNT signal, so we must have called sa1110_mb_disable() - * beforehand. - */ - sa1111_configure_smc(g_sa1111, 1, - FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), - FExtr(MDCNFG, MDCNFG_SA1110_TDL0)); - - /* - * We only need to turn on DCLK whenever we want to use the - * DMA. It can otherwise be held firmly in the off position. - */ - val = sa1111_readl(g_sa1111->base + SA1111_SKPCR); - sa1111_writel(val | SKPCR_DCLKEN, g_sa1111->base + SA1111_SKPCR); - - /* - * Enable the SA1110 memory bus request and grant signals. - */ - sa1110_mb_enable(); - - /* - * Initialise SA1111 IRQs - */ - int_dev.irq[0] = irq; - sa1111_init_irq(&int_dev); - - return 0; -} - struct sa1111_save_data { unsigned int skcr; unsigned int skpcr; @@ -717,7 +702,7 @@ static int sa1111_suspend(struct device *dev, u32 state, u32 level) { - struct sa1111 *sachip = dev->driver_data; + struct sa1111 *sachip = dev_get_drvdata(dev); unsigned long flags; char *base; @@ -789,7 +774,7 @@ */ static int sa1111_resume(struct device *dev, u32 level) { - struct sa1111 *sachip = dev->driver_data; + struct sa1111 *sachip = dev_get_drvdata(dev); struct sa1111_save_data *save; unsigned long flags, id; char *base; @@ -809,6 +794,7 @@ id = sa1111_readl(sachip->base + SA1111_SKID); if ((id & SKID_ID_MASK) != SKID_SA1111_ID) { __sa1111_remove(sachip); + dev_set_drvdata(dev, NULL); kfree(save); return 0; } @@ -840,18 +826,85 @@ return 0; } +static int sa1111_probe(struct device *dev) +{ + return -ENODEV; +} + +static int sa1111_remove(struct device *dev) +{ + struct sa1111 *sachip = dev_get_drvdata(dev); + + if (sachip) { + __sa1111_remove(sachip); + dev_set_drvdata(dev, NULL); + + kfree(dev->saved_state); + dev->saved_state = NULL; + } + + return 0; +} + +/* + * Not sure if this should be on the system bus or not yet. + * We really want some way to register a system device at + * the per-machine level, and then have this driver pick + * up the registered devices. + * + * We also need to handle the SDRAM configuration for + * PXA250/SA1110 machine classes. + */ static struct device_driver sa1111_device_driver = { + .name = "SA1111", + .bus = &system_bus_type, + .probe = sa1111_probe, + .remove = sa1111_remove, .suspend = sa1111_suspend, .resume = sa1111_resume, }; /* + * Register the SA1111 driver with LDM. + */ +static int sa1111_driver_init(void) +{ + driver_register(&sa1111_device_driver); + return 0; +} + +arch_initcall(sa1111_driver_init); + +static struct sys_device sa1111_device = { + .name = "SA1111", + .id = 0, + .root = NULL, + .dev = { + .name = "Intel Corporation SA1111", + .driver = &sa1111_device_driver, + }, +}; + +int sa1111_init(unsigned long phys, unsigned int irq) +{ + int ret; + + snprintf(sa1111_device.dev.bus_id, sizeof(sa1111_device.dev.bus_id), "%8.8lx", phys); + + ret = sys_device_register(&sa1111_device); + if (ret) + printk("sa1111 device_register failed: %d\n", ret); + + return __sa1111_probe(&sa1111_device.dev, phys, irq); +} + +/* * Get the parent device driver (us) structure * from a child function device */ static inline struct sa1111 *sa1111_chip_driver(struct sa1111_dev *sadev) { - return (struct sa1111 *)sadev->dev.parent->driver_data; + return (struct sa1111 *)dev_get_drvdata(sadev->dev.parent); } /* diff -Nru a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c --- a/arch/arm/mm/fault-armv.c Tue Oct 15 20:29:13 2002 +++ b/arch/arm/mm/fault-armv.c Tue Oct 15 20:29:13 2002 @@ -16,8 +16,10 @@ #include #include +#include #include #include +#include #include "fault.h" diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c --- a/arch/arm/mm/init.c Tue Oct 15 20:29:12 2002 +++ b/arch/arm/mm/init.c Tue Oct 15 20:29:12 2002 @@ -519,6 +519,10 @@ bdata->node_boot_start >> PAGE_SHIFT, zhole_size); } +#ifndef CONFIG_DISCONTIGMEM + mem_map = contig_page_data.node_mem_map; +#endif + /* * finish off the bad pages once * the mem_map is initialised @@ -559,7 +563,9 @@ initpages = &__init_end - &__init_begin; high_memory = (void *)__va(meminfo.end); +#ifndef CONFIG_DISCONTIGMEM max_mapnr = virt_to_page(high_memory) - mem_map; +#endif /* * We may have non-contiguous memory. diff -Nru a/arch/arm/mm/minicache.c b/arch/arm/mm/minicache.c --- a/arch/arm/mm/minicache.c Tue Oct 15 20:29:19 2002 +++ b/arch/arm/mm/minicache.c Tue Oct 15 20:29:19 2002 @@ -15,9 +15,11 @@ */ #include #include + #include #include #include +#include /* * 0xffff8000 to 0xffffffff is reserved for any ARM architecture diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c --- a/arch/arm/mm/mm-armv.c Tue Oct 15 20:29:17 2002 +++ b/arch/arm/mm/mm-armv.c Tue Oct 15 20:29:17 2002 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include @@ -213,6 +215,50 @@ pmd_clear(pmd_offset(pgd_offset_k(virt), virt)); } +struct mem_types { + unsigned int prot_pte; + unsigned int prot_sect; + unsigned int domain; +}; + +static struct mem_types mem_types[] __initdata = { + [MT_DEVICE] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_WRITE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE, + .domain = DOMAIN_IO, + }, + [MT_CACHECLEAN] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE | L_PTE_BUFFERABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | + PMD_SECT_BUFFERABLE, + .domain = DOMAIN_KERNEL, + }, + [MT_MINICLEAN] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE, + .domain = DOMAIN_KERNEL, + }, + [MT_VECTORS] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE | L_PTE_BUFFERABLE | + L_PTE_EXEC, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | + PMD_SECT_BUFFERABLE, + .domain = DOMAIN_USER, + }, + [MT_MEMORY] = { + .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | + L_PTE_CACHEABLE | L_PTE_BUFFERABLE | + L_PTE_EXEC | L_PTE_WRITE, + .prot_sect = PMD_TYPE_SECT | PMD_SECT_CACHEABLE | + PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE, + .domain = DOMAIN_KERNEL, + } +}; + /* * Create the page directory entries and any necessary * page tables for the mapping specified by `md'. We @@ -232,42 +278,9 @@ return; } - prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY; - prot_sect = PMD_TYPE_SECT; - - switch (md->type) { - case MT_DEVICE: - prot_pte |= L_PTE_WRITE; - prot_sect |= PMD_SECT_AP_WRITE; - domain = DOMAIN_IO; - break; - - case MT_CACHECLEAN: - prot_pte |= L_PTE_CACHEABLE | L_PTE_BUFFERABLE; - prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE; - domain = DOMAIN_KERNEL; - break; - - case MT_MINICLEAN: - prot_pte |= L_PTE_CACHEABLE; - prot_sect |= PMD_SECT_CACHEABLE; - domain = DOMAIN_KERNEL; - break; - - case MT_VECTORS: - prot_pte |= L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE; - prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE; - domain = DOMAIN_USER; - break; - - case MT_MEMORY: - prot_pte |= L_PTE_WRITE | L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE; - prot_sect |= PMD_SECT_AP_WRITE | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE; - domain = DOMAIN_KERNEL; - break; - } - - prot_sect |= PMD_DOMAIN(domain); + domain = mem_types[md->type].domain; + prot_pte = mem_types[md->type].prot_pte; + prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain); virt = md->virtual; off = md->physical - virt; diff -Nru a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c --- a/arch/arm/mm/proc-syms.c Tue Oct 15 20:29:16 2002 +++ b/arch/arm/mm/proc-syms.c Tue Oct 15 20:29:16 2002 @@ -10,8 +10,10 @@ #include #include +#include #include #include +#include #ifndef MULTI_CPU EXPORT_SYMBOL(cpu_cache_clean_invalidate_all); @@ -29,11 +31,11 @@ EXPORT_SYMBOL(processor); #endif -#ifndef MULTI_TLB -EXPORT_SYMBOL_NOVERS(__cpu_flush_kern_tlb_all); -EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_mm); -EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_range); -EXPORT_SYMBOL_NOVERS(__cpu_flush_user_tlb_page); -#else +/* + * No module should need to touch the TLB (and currently + * no modules do. We export this for "loadkernel" support + * (booting a new kernel from within a running kernel.) + */ +#ifdef MULTI_TLB EXPORT_SYMBOL(cpu_tlb); #endif diff -Nru a/arch/arm/mm/tlb-v3.S b/arch/arm/mm/tlb-v3.S --- a/arch/arm/mm/tlb-v3.S Tue Oct 15 20:29:11 2002 +++ b/arch/arm/mm/tlb-v3.S Tue Oct 15 20:29:11 2002 @@ -13,32 +13,11 @@ */ #include #include +#include #include "proc-macros.S" .align 5 /* - * v3_flush_user_tlb_mm(mm) - * - * Invalidate all TLB entries in a particular address space - * - * - mm - mm_struct describing address space - */ -ENTRY(v3_flush_user_tlb_mm) - act_mm r1 @ get current->active_mm - teq r0, r1 @ == mm ? - movne pc, lr @ no, we dont do anything - -/* - * v3_flush_kern_tlb_all() - * - * Invalidate the entire TLB - */ -ENTRY(v3_flush_kern_tlb_all) - mov r0, #0 - mcr p15, 0, r0, c5, c0, 0 @ invalidate TLB - mov pc, lr - -/* * v3_flush_user_tlb_range(start, end, mm) * * Invalidate a range of TLB entries in the specified address space. @@ -62,32 +41,11 @@ blo 1b mov pc, lr -/* - * v3_flush_user_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v3_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no -ENTRY(v3_flush_kern_tlb_page) - mcr p15, 0, r0, c6, c0, 0 @ invalidate TLB entry - mov pc, lr - .section ".text.init", #alloc, #execinstr .type v3_tlb_fns, #object ENTRY(v3_tlb_fns) - .long v3_flush_kern_tlb_all - .long v3_flush_user_tlb_mm .long v3_flush_user_tlb_range - .long v3_flush_user_tlb_page .long v3_flush_kern_tlb_range - .long v3_flush_kern_tlb_page + .long v3_tlb_flags .size v3_tlb_fns, . - v3_tlb_fns diff -Nru a/arch/arm/mm/tlb-v4.S b/arch/arm/mm/tlb-v4.S --- a/arch/arm/mm/tlb-v4.S Tue Oct 15 20:29:16 2002 +++ b/arch/arm/mm/tlb-v4.S Tue Oct 15 20:29:16 2002 @@ -14,32 +14,11 @@ */ #include #include +#include #include "proc-macros.S" .align 5 /* - * v4_flush_user_tlb_mm(mm) - * - * Invalidate all TLB entries in a particular address space - * - * - mm - mm_struct describing address space - */ -ENTRY(v4_flush_user_tlb_mm) - act_mm r1 @ get current->active_mm - teq r0, r1 @ == mm ? - movne pc, lr @ no, we dont do anything - -/* - * v4_flush_kern_tlb_all() - * - * Invalidate the entire TLB - */ -ENTRY(v4_flush_kern_tlb_all) - mov r0, #0 - mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs - mov pc, lr - -/* * v4_flush_user_tlb_range(start, end, mm) * * Invalidate a range of TLB entries in the specified user address space. @@ -65,25 +44,6 @@ mov pc, lr /* - * v4_flush_user_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v4_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no - vma_vm_flags r2, r1 -.v4_flush_kern_tlb_page: - mcr p15, 0, r0, c8, c7, 1 @ invalidate TLB entry - mov pc, lr - -/* * v4_flush_kerm_tlb_range(start, end) * * Invalidate a range of TLB entries in the specified kernel @@ -95,27 +55,11 @@ .globl v4_flush_kern_tlb_range .equ v4_flush_kern_tlb_range, .v4_flush_kern_tlb_range - -/* - * v4_flush_kern_tlb_page(kaddr) - * - * Invalidate the TLB entry for the specified page. The address - * will be in the kernels virtual memory space. Current uses - * only require the D-TLB to be invalidated. - * - * - kaddr - Kernel virtual memory address - */ -.globl v4_flush_kern_tlb_page -.equ v4_flush_kern_tlb_page, .v4_flush_kern_tlb_page - .section ".text.init", #alloc, #execinstr .type v4_tlb_fns, #object ENTRY(v4_tlb_fns) - .long v4_flush_kern_tlb_all - .long v4_flush_user_tlb_mm .long v4_flush_user_tlb_range - .long v4_flush_user_tlb_page .long v4_flush_kern_tlb_range - .long v4_flush_kern_tlb_page + .long v4_tlb_flags .size v4_tlb_fns, . - v4_tlb_fns diff -Nru a/arch/arm/mm/tlb-v4wb.S b/arch/arm/mm/tlb-v4wb.S --- a/arch/arm/mm/tlb-v4wb.S Tue Oct 15 20:29:15 2002 +++ b/arch/arm/mm/tlb-v4wb.S Tue Oct 15 20:29:15 2002 @@ -14,35 +14,11 @@ */ #include #include +#include #include "proc-macros.S" .align 5 /* - * v4wb_flush_user_tlb_mm(mm) - * - * Invalidate all TLB entries in a particular address space - * - * - mm - mm_struct describing address space - */ -ENTRY(v4wb_flush_user_tlb_mm) -ENTRY(v4wbi_flush_user_tlb_mm) - act_mm r1 @ get current->active_mm - teq r0, r1 @ == mm ? - movne pc, lr @ no, we dont do anything - -/* - * v4wb_flush_tlb_all() - * - * Invalidate the entire TLB - */ -ENTRY(v4wb_flush_kern_tlb_all) -ENTRY(v4wbi_flush_kern_tlb_all) - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c7, 0 @ invalidate I + D TLBs - mov pc, lr - -/* * v4wb_flush_user_tlb_range(start, end, mm) * * Invalidate a range of TLB entries in the specified address space. @@ -70,28 +46,6 @@ mov pc, lr /* - * v4wb_flush_user_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v4wb_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no - vma_vm_flags r2, r1 - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - tst r2, #VM_EXEC - mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - -/* * v4_flush_kerm_tlb_range(start, end) * * Invalidate a range of TLB entries in the specified kernel @@ -113,20 +67,6 @@ mov pc, lr /* - * v4_flush_kern_tlb_page(kaddr) - * - * Invalidate the TLB entry for the specified page. The address - * will be in the kernels virtual memory space. Current uses - * only require the D-TLB to be invalidated. - * - * - kaddr - Kernel virtual memory address - */ -ENTRY(v4wb_flush_kern_tlb_page) - mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - -/* * These two are optimised for ARM920, ARM922, ARM926, Xscale */ @@ -158,28 +98,6 @@ blo 1b mov pc, lr -/* - * v4wb_flush_tlb_page(vaddr,vma) - * - * Invalidate the specified page in the specified address space. - * - * - vaddr - virtual address (may not be aligned) - * - vma - vma_struct describing address range - */ - .align 5 -ENTRY(v4wbi_flush_user_tlb_page) - vma_vm_mm r2, r1 @ get vma->vm_mm - act_mm r3 @ get current->active_mm - teq r2, r3 @ equal - movne pc, lr @ no - vma_vm_flags r2, r1 - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - tst r2, #VM_EXEC - mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - ENTRY(v4wbi_flush_kern_tlb_range) mov r3, #0 mcr p15, 0, r3, c7, c10, 4 @ drain WB @@ -192,29 +110,18 @@ blo 1b mov pc, lr -ENTRY(v4wbi_flush_kern_tlb_page) - mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry - mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry - mov pc, lr - .section ".text.init", #alloc, #execinstr .type v4wb_tlb_fns, #object ENTRY(v4wb_tlb_fns) - .long v4wb_flush_kern_tlb_all - .long v4wb_flush_user_tlb_mm .long v4wb_flush_user_tlb_range - .long v4wb_flush_user_tlb_page .long v4wb_flush_kern_tlb_range - .long v4wb_flush_kern_tlb_page + .long v4wb_tlb_flags .size v4wb_tlb_fns, . - v4wb_tlb_fns .type v4wbi_tlb_fns, #object ENTRY(v4wbi_tlb_fns) - .long v4wbi_flush_kern_tlb_all - .long v4wbi_flush_user_tlb_mm .long v4wbi_flush_user_tlb_range - .long v4wbi_flush_user_tlb_page .long v4wbi_flush_kern_tlb_range - .long v4wbi_flush_kern_tlb_page + .long v4wbi_tlb_flags .size v4wbi_tlb_fns, . - v4wbi_tlb_fns diff -Nru a/arch/arm/vmlinux.lds.S b/arch/arm/vmlinux.lds.S --- a/arch/arm/vmlinux.lds.S Tue Oct 15 20:29:11 2002 +++ b/arch/arm/vmlinux.lds.S Tue Oct 15 20:29:11 2002 @@ -4,13 +4,10 @@ #ifdef CONFIG_ROM_KERNEL -#define DATAADDR 0x02080000 -#define TEXTADDR 0x03800000 #include "vmlinux-armo-rom.lds.in" #else -#define TEXTADDR 0x02080000 #include "vmlinux-armo.lds.in" #endif @@ -19,7 +16,6 @@ #ifdef CONFIG_CPU_32 -#define TEXTADDR 0xC0008000 #include "vmlinux-armv.lds.in" #endif diff -Nru a/arch/cris/drivers/examples/kiobuftest.c b/arch/cris/drivers/examples/kiobuftest.c --- a/arch/cris/drivers/examples/kiobuftest.c Tue Oct 15 20:29:22 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,111 +0,0 @@ -/* - * Example showing how to pin down a range of virtual pages from user-space - * to be able to do for example DMA directly into them. - * - * It is necessary because the pages the virtual pointers reference, might - * not exist in memory (could be mapped to the zero-page, filemapped etc) - * and DMA cannot trigger the MMU to force them in (and would have time - * contraints making it impossible to wait for it anyway). - * - * Author: Bjorn Wesen - * - * $Log: kiobuftest.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 - * - * Revision 1.2 2001/02/27 13:52:50 bjornw - * malloc.h -> slab.h - * - * Revision 1.1 2001/01/19 15:57:49 bjornw - * Example of how to do direct HW -> user-mode DMA - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KIOBUFTEST_MAJOR 124 /* in the local range, experimental */ - - -static ssize_t -kiobuf_read(struct file *filp, char *buf, size_t len, loff_t *ppos) -{ - - struct kiobuf *iobuf; - int res, i; - - /* Make a kiobuf that maps the entire length the reader has given - * us - */ - - res = alloc_kiovec(1, &iobuf); - if (res) - return res; - - if((res = map_user_kiobuf(READ, iobuf, (unsigned long)buf, len))) { - printk("map_user_kiobuf failed, return %d\n", res); - return res; - } - - /* At this point, the virtual area buf[0] -> buf[len-1] will - * have corresponding pages mapped in physical memory and locked - * until we unmap the kiobuf. They cannot be swapped out or moved - * around. - */ - - printk("nr_pages == %d\noffset == %d\nlength == %d\n", - iobuf->nr_pages, iobuf->offset, iobuf->length); - - for(i = 0; i < iobuf->nr_pages; i++) { - printk("page_add(maplist[%d]) == 0x%x\n", i, - page_address(iobuf->maplist[i])); - } - - /* This is the place to create the necessary scatter-gather vector - * for the DMA using the iobuf->maplist array and page_address - * (don't forget __pa if the DMA needs the actual physical DRAM address) - * and run it. - */ - - - - - /* Release the mapping and exit */ - - unmap_kiobuf(iobuf); /* The unlock_kiobuf is implicit here */ - - return len; -} - - -static struct file_operations kiobuf_fops = { - owner: THIS_MODULE, - read: kiobuf_read -}; - -static int __init -kiobuftest_init(void) -{ - int res; - - /* register char device */ - - res = register_chrdev(KIOBUFTEST_MAJOR, "kiobuftest", &kiobuf_fops); - if(res < 0) { - printk(KERN_ERR "kiobuftest: couldn't get a major number.\n"); - return res; - } - - printk("Initializing kiobuf-test device\n"); -} - -module_init(kiobuftest_init); diff -Nru a/arch/i386/Config.help b/arch/i386/Config.help --- a/arch/i386/Config.help Tue Oct 15 20:29:12 2002 +++ b/arch/i386/Config.help Tue Oct 15 20:29:12 2002 @@ -73,6 +73,12 @@ If you are suffering from time skew using a multi-CEC system, say YES. Otherwise it is safe to say NO. +CONFIG_X86_SUMMIT + This option is needed for IBM systems that use the Summit/EXA chipset. + In particular, it is needed for the x440. + + If you don't have one of these computers, you should say N here. + CONFIG_X86_UP_IOAPIC An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an SMP-capable replacement for PC-style interrupt controllers. Most @@ -1048,6 +1054,11 @@ Say Y here if you want to reduce the chances of the tree compiling, and are prepared to dig into driver internals to fix compile errors. +Profiling support +CONFIG_PROFILING + Say Y here to enable the extended profiling support mechanisms used + by profilers such as OProfile. + Software Suspend CONFIG_SOFTWARE_SUSPEND Enable the possibilty of suspendig machine. It doesn't need APM. diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile --- a/arch/i386/Makefile Tue Oct 15 20:29:16 2002 +++ b/arch/i386/Makefile Tue Oct 15 20:29:16 2002 @@ -57,6 +57,8 @@ arch/i386/$(MACHINE)/ drivers-$(CONFIG_MATH_EMULATION) += arch/i386/math-emu/ drivers-$(CONFIG_PCI) += arch/i386/pci/ +# FIXME: is drivers- right ? +drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ CFLAGS += -Iarch/i386/$(MACHINE) AFLAGS += -Iarch/i386/$(MACHINE) diff -Nru a/arch/i386/config.in b/arch/i386/config.in --- a/arch/i386/config.in Tue Oct 15 20:29:15 2002 +++ b/arch/i386/config.in Tue Oct 15 20:29:15 2002 @@ -172,7 +172,8 @@ if [ "$CONFIG_X86_NUMA" = "y" ]; then #Platform Choices bool 'Multiquad (IBM/Sequent) NUMAQ support' CONFIG_X86_NUMAQ - if [ "$CONFIG_X86_NUMAQ" = "y" ]; then + bool 'IBM x440 (Summit/EXA) support' CONFIG_X86_SUMMIT + if [ "$CONFIG_X86_NUMAQ" = "y" -o "$CONFIG_X86_SUMMIT" = "y" ]; then define_bool CONFIG_CLUSTERED_APIC y fi # Common NUMA Features @@ -442,6 +443,8 @@ source net/bluetooth/Config.in +source arch/i386/oprofile/Config.in + mainmenu_option next_comment comment 'Kernel hacking' if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Tue Oct 15 20:29:12 2002 +++ b/arch/i386/kernel/Makefile Tue Oct 15 20:29:12 2002 @@ -27,6 +27,7 @@ obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o obj-$(CONFIG_X86_NUMAQ) += numaq.o +obj-$(CONFIG_PROFILING) += profile.o EXTRA_AFLAGS := -traditional diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c --- a/arch/i386/kernel/apic.c Tue Oct 15 20:29:23 2002 +++ b/arch/i386/kernel/apic.c Tue Oct 15 20:29:23 2002 @@ -31,6 +31,7 @@ #include #include #include +#include "mach_apic.h" void __init apic_intr_init(void) { @@ -328,15 +329,13 @@ * Put the APIC into flat delivery mode. * Must be "all ones" explicitly for 82489DX. */ - apic_write_around(APIC_DFR, 0xffffffff); + apic_write_around(APIC_DFR, APIC_DFR_VALUE); /* * Set up the logical destination ID. */ value = apic_read(APIC_LDR); - value &= ~APIC_LDR_MASK; - value |= (1<<(smp_processor_id()+24)); - apic_write_around(APIC_LDR, value); + apic_write_around(APIC_LDR, calculate_ldr(value)); } /* @@ -1008,17 +1007,9 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs) { - int user = user_mode(regs); int cpu = smp_processor_id(); - /* - * The profiling function is SMP safe. (nothing can mess - * around with "current", and the profiling counters are - * updated with atomic operations). This is especially - * useful with a profiling multiplier != 1 - */ - if (!user) - x86_do_profile(regs->eip); + x86_do_profile(regs); if (--prof_counter[cpu] <= 0) { /* @@ -1036,7 +1027,7 @@ } #ifdef CONFIG_SMP - update_process_times(user); + update_process_times(user_mode(regs)); #endif } diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c --- a/arch/i386/kernel/dmi_scan.c Tue Oct 15 20:29:16 2002 +++ b/arch/i386/kernel/dmi_scan.c Tue Oct 15 20:29:16 2002 @@ -31,7 +31,7 @@ if(!s) return ""; s--; - while(s>0) + while(s>0 && *bp) { bp+=strlen(bp); bp++; @@ -50,7 +50,7 @@ u8 *buf; struct dmi_header *dm; u8 *data; - int i=1; + int i=0; buf = bt_ioremap(base, len); if(buf==NULL) @@ -59,28 +59,23 @@ data = buf; /* - * Stop when we see al the items the table claimed to have + * Stop when we see all the items the table claimed to have * OR we run off the end of the table (also happens) */ - while(ilength) >= len) - break; - decode(dm); data+=dm->length; - /* - * Don't go off the end of the data if there is - * stuff looking like string fill past the end - */ - while((data-buf) < len && (*data || data[1])) + while(data-buf>4, buf[14]&0x0F)); + /* + * DMI version 0.0 means that the real version is taken from + * the SMBIOS version, which we don't know at this point. + */ + if(buf[14]!=0) + dmi_printk((KERN_INFO "DMI %d.%d present.\n", + buf[14]>>4, buf[14]&0x0F)); + else + dmi_printk((KERN_INFO "DMI present.\n")); dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n", - buf[13]<<8|buf[12], - buf[7]<<8|buf[6])); + num, len)); dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", - buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8])); + base)); if(dmi_table(base,len, num, decode)==0) return 0; } + fp+=16; } return -1; } @@ -823,59 +833,43 @@ static void __init dmi_decode(struct dmi_header *dm) { u8 *data = (u8 *)dm; - char *p; switch(dm->type) { case 0: - p=dmi_string(dm,data[4]); - if(*p) - { - dmi_printk(("BIOS Vendor: %s\n", p)); - dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); - dmi_printk(("BIOS Version: %s\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_BIOS_VERSION, 5); - dmi_printk(("BIOS Release: %s\n", - dmi_string(dm, data[8]))); - dmi_save_ident(dm, DMI_BIOS_DATE, 8); - } + dmi_printk(("BIOS Vendor: %s\n", + dmi_string(dm, data[4]))); + dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); + dmi_printk(("BIOS Version: %s\n", + dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BIOS_VERSION, 5); + dmi_printk(("BIOS Release: %s\n", + dmi_string(dm, data[8]))); + dmi_save_ident(dm, DMI_BIOS_DATE, 8); break; - case 1: - p=dmi_string(dm,data[4]); - if(*p) - { - dmi_printk(("System Vendor: %s.\n",p)); - dmi_save_ident(dm, DMI_SYS_VENDOR, 4); - dmi_printk(("Product Name: %s.\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); - dmi_printk(("Version %s.\n", - dmi_string(dm, data[6]))); - dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); - dmi_printk(("Serial Number %s.\n", - dmi_string(dm, data[7]))); - } + dmi_printk(("System Vendor: %s\n", + dmi_string(dm, data[4]))); + dmi_save_ident(dm, DMI_SYS_VENDOR, 4); + dmi_printk(("Product Name: %s\n", + dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); + dmi_printk(("Version: %s\n", + dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); + dmi_printk(("Serial Number: %s\n", + dmi_string(dm, data[7]))); break; case 2: - p=dmi_string(dm,data[4]); - if(*p) - { - dmi_printk(("Board Vendor: %s.\n",p)); - dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); - dmi_printk(("Board Name: %s.\n", - dmi_string(dm, data[5]))); - dmi_save_ident(dm, DMI_BOARD_NAME, 5); - dmi_printk(("Board Version: %s.\n", - dmi_string(dm, data[6]))); - dmi_save_ident(dm, DMI_BOARD_VERSION, 6); - } - break; - case 3: - p=dmi_string(dm,data[8]); - if(*p && *p!=' ') - dmi_printk(("Asset Tag: %s.\n", p)); + dmi_printk(("Board Vendor: %s\n", + dmi_string(dm, data[4]))); + dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); + dmi_printk(("Board Name: %s\n", + dmi_string(dm, data[5]))); + dmi_save_ident(dm, DMI_BOARD_NAME, 5); + dmi_printk(("Board Version: %s\n", + dmi_string(dm, data[6]))); + dmi_save_ident(dm, DMI_BOARD_VERSION, 6); break; } } diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S Tue Oct 15 20:29:15 2002 +++ b/arch/i386/kernel/entry.S Tue Oct 15 20:29:15 2002 @@ -736,6 +736,7 @@ .long sys_alloc_hugepages /* 250 */ .long sys_free_hugepages .long sys_exit_group + .long sys_lookup_dcookie .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c Tue Oct 15 20:29:23 2002 +++ b/arch/i386/kernel/i386_ksyms.c Tue Oct 15 20:29:23 2002 @@ -29,6 +29,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -151,6 +152,10 @@ EXPORT_SYMBOL(flush_tlb_page); #endif +#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM) +EXPORT_SYMBOL_GPL(set_nmi_pm_callback); +EXPORT_SYMBOL_GPL(unset_nmi_pm_callback); +#endif #ifdef CONFIG_X86_IO_APIC EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); #endif @@ -167,6 +172,11 @@ EXPORT_SYMBOL(rtc_lock); +EXPORT_SYMBOL_GPL(register_profile_notifier); +EXPORT_SYMBOL_GPL(unregister_profile_notifier); +EXPORT_SYMBOL_GPL(set_nmi_callback); +EXPORT_SYMBOL_GPL(unset_nmi_callback); + #undef memcpy #undef memset extern void * memset(void *,int,__kernel_size_t); diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c Tue Oct 15 20:29:15 2002 +++ b/arch/i386/kernel/io_apic.c Tue Oct 15 20:29:15 2002 @@ -35,6 +35,7 @@ #include #include #include +#include "mach_apic.h" #undef APIC_LOCKUP_DEBUG @@ -1151,7 +1152,7 @@ old_id = mp_ioapics[apic].mpc_apicid; - if (mp_ioapics[apic].mpc_apicid >= 0xf) { + if (mp_ioapics[apic].mpc_apicid >= APIC_BROADCAST_ID) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", apic, mp_ioapics[apic].mpc_apicid); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", @@ -1164,7 +1165,8 @@ * system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. */ - if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) { + if (check_apicid_used(phys_id_present_map, + mp_ioapics[apic].mpc_apicid)) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", apic, mp_ioapics[apic].mpc_apicid); for (i = 0; i < 0xf; i++) diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c --- a/arch/i386/kernel/ldt.c Tue Oct 15 20:29:19 2002 +++ b/arch/i386/kernel/ldt.c Tue Oct 15 20:29:19 2002 @@ -20,10 +20,10 @@ #include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ -static void flush_ldt(void *mm) +static void flush_ldt(void *null) { - if (current->mm) - load_LDT(¤t->mm->context); + if (current->active_mm) + load_LDT(¤t->active_mm->context); } #endif diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c --- a/arch/i386/kernel/mpparse.c Tue Oct 15 20:29:15 2002 +++ b/arch/i386/kernel/mpparse.c Tue Oct 15 20:29:15 2002 @@ -30,6 +30,7 @@ #include #include #include +#include "mach_apic.h" /* Have we found an MP table */ int smp_found_config; @@ -69,6 +70,9 @@ /* Bitmask of physically existing CPUs */ unsigned long phys_cpu_present_map; +int summit_x86 = 0; +u8 raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; + /* * Intel MP BIOS table parsing routines: */ @@ -189,7 +193,7 @@ if (clustered_apic_mode) { phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad); } else { - phys_cpu_present_map |= 1 << m->mpc_apicid; + phys_cpu_present_map |= apicid_to_cpu_present(m->mpc_apicid); } /* * Validate version @@ -199,6 +203,7 @@ ver = 0x10; } apic_version[m->mpc_apicid] = ver; + raw_phys_apicid[num_processors - 1] = m->mpc_apicid; } static void __init MP_bus_info (struct mpc_config_bus *m) @@ -356,6 +361,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) { char str[16]; + char oem[10]; int count=sizeof(*mpc); unsigned char *mpt=((unsigned char *)mpc)+count; @@ -380,14 +386,16 @@ printk(KERN_ERR "SMP mptable: null local APIC address!\n"); return 0; } - memcpy(str,mpc->mpc_oem,8); - str[8]=0; - printk("OEM ID: %s ",str); + memcpy(oem,mpc->mpc_oem,8); + oem[8]=0; + printk("OEM ID: %s ",oem); memcpy(str,mpc->mpc_productid,12); str[12]=0; printk("Product ID: %s ",str); + summit_check(oem, str); + printk("APIC at: 0x%lX\n",mpc->mpc_lapic); /* @@ -465,6 +473,7 @@ } ++mpc_record; } + clustered_apic_check(); if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c --- a/arch/i386/kernel/nmi.c Tue Oct 15 20:29:17 2002 +++ b/arch/i386/kernel/nmi.c Tue Oct 15 20:29:17 2002 @@ -175,6 +175,18 @@ return 0; } +struct pm_dev * set_nmi_pm_callback(pm_callback callback) +{ + apic_pm_unregister(nmi_pmdev); + return apic_pm_register(PM_SYS_DEV, 0, callback); +} + +void unset_nmi_pm_callback(struct pm_dev * dev) +{ + apic_pm_unregister(dev); + nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); +} + static void nmi_pm_init(void) { if (!nmi_pmdev) diff -Nru a/arch/i386/kernel/profile.c b/arch/i386/kernel/profile.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/kernel/profile.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,45 @@ +/* + * linux/arch/i386/kernel/profile.c + * + * (C) 2002 John Levon + * + */ + +#include +#include +#include +#include +#include + +static struct notifier_block * profile_listeners; +static rwlock_t profile_lock = RW_LOCK_UNLOCKED; + +int register_profile_notifier(struct notifier_block * nb) +{ + int err; + write_lock_irq(&profile_lock); + err = notifier_chain_register(&profile_listeners, nb); + write_unlock_irq(&profile_lock); + return err; +} + + +int unregister_profile_notifier(struct notifier_block * nb) +{ + int err; + write_lock_irq(&profile_lock); + err = notifier_chain_unregister(&profile_listeners, nb); + write_unlock_irq(&profile_lock); + return err; +} + + +void x86_profile_hook(struct pt_regs * regs) +{ + /* we would not even need this lock if + * we had a global cli() on register/unregister + */ + read_lock(&profile_lock); + notifier_call_chain(&profile_listeners, 0, regs); + read_unlock(&profile_lock); +} diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Tue Oct 15 20:29:17 2002 +++ b/arch/i386/kernel/smpboot.c Tue Oct 15 20:29:17 2002 @@ -51,6 +51,7 @@ #include #include #include "smpboot_hooks.h" +#include "mach_apic.h" /* Set if we find a B stepping CPU */ static int __initdata smp_b_stepping; diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c --- a/arch/i386/kernel/time.c Tue Oct 15 20:29:17 2002 +++ b/arch/i386/kernel/time.c Tue Oct 15 20:29:17 2002 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -64,11 +63,6 @@ extern spinlock_t i8259A_lock; #include "do_timer.h" - -/* - * for x86_do_profile() - */ -#include u64 jiffies_64; diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c --- a/arch/i386/kernel/timers/timer_tsc.c Tue Oct 15 20:29:18 2002 +++ b/arch/i386/kernel/timers/timer_tsc.c Tue Oct 15 20:29:19 2002 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Tue Oct 15 20:29:12 2002 +++ b/arch/i386/kernel/traps.c Tue Oct 15 20:29:12 2002 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -478,17 +479,16 @@ return; } #endif - printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); + printk("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", + reason, smp_processor_id()); printk("Dazed and confused, but trying to continue\n"); printk("Do you have a strange power saving mode enabled?\n"); } -asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +static void default_do_nmi(struct pt_regs * regs) { unsigned char reason = inb(0x61); - - ++nmi_count(smp_processor_id()); - + if (!(reason & 0xc0)) { #if CONFIG_X86_LOCAL_APIC /* @@ -515,6 +515,33 @@ inb(0x71); /* dummy */ outb(0x0f, 0x70); inb(0x71); /* dummy */ +} + +static int dummy_nmi_callback(struct pt_regs * regs, int cpu) +{ + return 0; +} + +static nmi_callback_t nmi_callback = dummy_nmi_callback; + +asmlinkage void do_nmi(struct pt_regs * regs, long error_code) +{ + int cpu = smp_processor_id(); + + ++nmi_count(cpu); + + if (!nmi_callback(regs, cpu)) + default_do_nmi(regs); +} + +void set_nmi_callback(nmi_callback_t callback) +{ + nmi_callback = callback; +} + +void unset_nmi_callback(void) +{ + nmi_callback = dummy_nmi_callback; } /* diff -Nru a/arch/i386/mach-generic/do_timer.h b/arch/i386/mach-generic/do_timer.h --- a/arch/i386/mach-generic/do_timer.h Tue Oct 15 20:29:21 2002 +++ b/arch/i386/mach-generic/do_timer.h Tue Oct 15 20:29:21 2002 @@ -20,8 +20,7 @@ * system, in that case we have to call the local interrupt handler. */ #ifndef CONFIG_X86_LOCAL_APIC - if (!user_mode(regs)) - x86_do_profile(regs->eip); + x86_do_profile(regs); #else if (!using_apic_timer) smp_local_timer_interrupt(regs); diff -Nru a/arch/i386/mach-generic/mach_apic.h b/arch/i386/mach-generic/mach_apic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-generic/mach_apic.h Tue Oct 15 20:29:25 2002 @@ -0,0 +1,46 @@ +#ifndef __ASM_MACH_APIC_H +#define __ASM_MACH_APIC_H + +static inline unsigned long calculate_ldr(unsigned long old) +{ + unsigned long id; + + id = 1UL << smp_processor_id(); + return ((old & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(id)); +} + +#define APIC_DFR_VALUE (APIC_DFR_FLAT) + +#ifdef CONFIG_SMP + #define TARGET_CPUS (clustered_apic_mode ? 0xf : cpu_online_map) +#else + #define TARGET_CPUS 0x01 +#endif + +#define APIC_BROADCAST_ID 0x0F +#define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid)) + +static inline void summit_check(char *oem, char *productid) +{ +} + +static inline void clustered_apic_check(void) +{ + printk("Enabling APIC mode: %s. Using %d I/O APICs\n", + (clustered_apic_mode ? "NUMA-Q" : "Flat"), nr_ioapics); +} + +static inline int cpu_present_to_apicid(int mps_cpu) +{ + if (clustered_apic_mode) + return ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) ); + else + return mps_cpu; +} + +static inline unsigned long apicid_to_cpu_present(int apicid) +{ + return (1ul << apicid); +} + +#endif /* __ASM_MACH_APIC_H */ diff -Nru a/arch/i386/mach-summit/mach_apic.h b/arch/i386/mach-summit/mach_apic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/mach-summit/mach_apic.h Tue Oct 15 20:29:25 2002 @@ -0,0 +1,57 @@ +#ifndef __ASM_MACH_APIC_H +#define __ASM_MACH_APIC_H + +extern int x86_summit; + +#define XAPIC_DEST_CPUS_MASK 0x0Fu +#define XAPIC_DEST_CLUSTER_MASK 0xF0u + +#define xapic_phys_to_log_apicid(phys_apic) ( (1ul << ((phys_apic) & 0x3)) |\ + ((phys_apic) & XAPIC_DEST_CLUSTER_MASK) ) + +static inline unsigned long calculate_ldr(unsigned long old) +{ + unsigned long id; + + if (x86_summit) + id = xapic_phys_to_log_apicid(hard_smp_processor_id()); + else + id = 1UL << smp_processor_id(); + return ((old & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(id)); +} + +#define APIC_DFR_VALUE (x86_summit ? APIC_DFR_CLUSTER : APIC_DFR_FLAT) +#define TARGET_CPUS (x86_summit ? XAPIC_DEST_CPUS_MASK : cpu_online_map) + +#define APIC_BROADCAST_ID (x86_summit ? 0xFF : 0x0F) +#define check_apicid_used(bitmap, apicid) (0) + +static inline void summit_check(char *oem, char *productid) +{ + if (!strncmp(oem, "IBM ENSW", 8) && !strncmp(str, "VIGIL SMP", 9)) + x86_summit = 1; +} + +static inline void clustered_apic_check(void) +{ + printk("Enabling APIC mode: %s. Using %d I/O APICs\n", + (x86_summit ? "Summit" : "Flat"), nr_ioapics); +} + +static inline int cpu_present_to_apicid(int mps_cpu) +{ + if (x86_summit) + return (int) raw_phys_apicid[mps_cpu]; + else + return mps_cpu; +} + +static inline unsigned long apicid_to_phys_cpu_present(int apicid) +{ + if (x86_summit) + return (1ul << (((apicid >> 4) << 2) | (apicid & 0x3))); + else + return (1ul << apicid); +} + +#endif /* __ASM_MACH_APIC_H */ diff -Nru a/arch/i386/mach-visws/do_timer.h b/arch/i386/mach-visws/do_timer.h --- a/arch/i386/mach-visws/do_timer.h Tue Oct 15 20:29:15 2002 +++ b/arch/i386/mach-visws/do_timer.h Tue Oct 15 20:29:15 2002 @@ -15,8 +15,7 @@ * system, in that case we have to call the local interrupt handler. */ #ifndef CONFIG_X86_LOCAL_APIC - if (!user_mode(regs)) - x86_do_profile(regs->eip); + x86_do_profile(regs); #else if (!using_apic_timer) smp_local_timer_interrupt(regs); diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c --- a/arch/i386/mm/discontig.c Tue Oct 15 20:29:17 2002 +++ b/arch/i386/mm/discontig.c Tue Oct 15 20:29:17 2002 @@ -70,6 +70,7 @@ node_datasz = PFN_UP(sizeof(struct pglist_data)); NODE_DATA(nid) = (pg_data_t *)(__va(min_low_pfn << PAGE_SHIFT)); min_low_pfn += node_datasz; + memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); } /* diff -Nru a/arch/i386/oprofile/Config.help b/arch/i386/oprofile/Config.help --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/Config.help Tue Oct 15 20:29:23 2002 @@ -0,0 +1,6 @@ +CONFIG_OPROFILE + OProfile is a profiling system capable of profiling the + whole system, include the kernel, kernel modules, libraries, + and applications. + + If unsure, say N. diff -Nru a/arch/i386/oprofile/Config.in b/arch/i386/oprofile/Config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/Config.in Tue Oct 15 20:29:25 2002 @@ -0,0 +1,9 @@ +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + mainmenu_option next_comment + comment 'Profiling support' + bool 'Profiling support (EXPERIMENTAL)' CONFIG_PROFILING + if [ "$CONFIG_PROFILING" = "y" ]; then + tristate ' OProfile system profiling (EXPERIMENTAL)' CONFIG_OPROFILE + fi + endmenu +fi diff -Nru a/arch/i386/oprofile/Makefile b/arch/i386/oprofile/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/Makefile Tue Oct 15 20:29:25 2002 @@ -0,0 +1,16 @@ +vpath %.c = . $(TOPDIR)/drivers/oprofile + +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o ) + +oprofile-objs := $(DRIVER_OBJS) init.o timer_int.o + +ifdef CONFIG_X86_LOCAL_APIC +oprofile-objs += nmi_int.o op_model_athlon.o op_model_ppro.o +endif + +include $(TOPDIR)/Rules.make diff -Nru a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/init.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,30 @@ +/** + * @file init.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include + +/* We support CPUs that have performance counters like the Pentium Pro + * with NMI mode samples. Other x86 CPUs use a simple interrupt keyed + * off the timer interrupt, which cannot profile interrupts-disabled + * code unlike the NMI-based code. + */ + +extern int nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu); +extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu); + +int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu) +{ +#ifdef CONFIG_X86_LOCAL_APIC + if (!nmi_init(ops, cpu)) +#endif + timer_init(ops, cpu); + return 0; +} diff -Nru a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/nmi_int.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,258 @@ +/** + * @file nmi_int.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "op_counter.h" +#include "op_x86_model.h" + +static struct op_x86_model_spec const * model; +static struct op_msrs cpu_msrs[NR_CPUS]; +static unsigned long saved_lvtpc[NR_CPUS]; +static unsigned long kernel_only; + +static int nmi_start(void); +static void nmi_stop(void); + +static struct pm_dev * oprofile_pmdev; + +/* We're at risk of causing big trouble unless we + * make sure to not cause any NMI interrupts when + * suspended. + */ +static int oprofile_pm_callback(struct pm_dev * dev, + pm_request_t rqst, void * data) +{ + switch (rqst) { + case PM_SUSPEND: + nmi_stop(); + break; + case PM_RESUME: + nmi_start(); + break; + } + return 0; +} + + +// FIXME: kernel_only +static int nmi_callback(struct pt_regs * regs, int cpu) +{ + return (model->check_ctrs(cpu, &cpu_msrs[cpu], regs)); +} + + +static void nmi_save_registers(struct op_msrs * msrs) +{ + unsigned int const nr_ctrs = model->num_counters; + unsigned int const nr_ctrls = model->num_controls; + struct op_msr_group * counters = &msrs->counters; + struct op_msr_group * controls = &msrs->controls; + int i; + + for (i = 0; i < nr_ctrs; ++i) { + rdmsr(counters->addrs[i], + counters->saved[i].low, + counters->saved[i].high); + } + + for (i = 0; i < nr_ctrls; ++i) { + rdmsr(controls->addrs[i], + controls->saved[i].low, + controls->saved[i].high); + } +} + + +static void nmi_cpu_setup(void * dummy) +{ + int cpu = smp_processor_id(); + struct op_msrs * msrs = &cpu_msrs[cpu]; + model->fill_in_addresses(msrs); + nmi_save_registers(msrs); + spin_lock(&oprofilefs_lock); + model->setup_ctrs(msrs); + spin_unlock(&oprofilefs_lock); + saved_lvtpc[cpu] = apic_read(APIC_LVTPC); + apic_write(APIC_LVTPC, APIC_DM_NMI); +} + + +static int nmi_setup(void) +{ + /* We walk a thin line between law and rape here. + * We need to be careful to install our NMI handler + * without actually triggering any NMIs as this will + * break the core code horrifically. + */ + smp_call_function(nmi_cpu_setup, NULL, 0, 1); + nmi_cpu_setup(0); + set_nmi_callback(nmi_callback); + oprofile_pmdev = set_nmi_pm_callback(oprofile_pm_callback); + return 0; +} + + +static void nmi_restore_registers(struct op_msrs * msrs) +{ + unsigned int const nr_ctrs = model->num_counters; + unsigned int const nr_ctrls = model->num_controls; + struct op_msr_group * counters = &msrs->counters; + struct op_msr_group * controls = &msrs->controls; + int i; + + for (i = 0; i < nr_ctrls; ++i) { + wrmsr(controls->addrs[i], + controls->saved[i].low, + controls->saved[i].high); + } + + for (i = 0; i < nr_ctrs; ++i) { + wrmsr(counters->addrs[i], + counters->saved[i].low, + counters->saved[i].high); + } +} + + +static void nmi_cpu_shutdown(void * dummy) +{ + int cpu = smp_processor_id(); + struct op_msrs * msrs = &cpu_msrs[cpu]; + apic_write(APIC_LVTPC, saved_lvtpc[cpu]); + nmi_restore_registers(msrs); +} + + +static void nmi_shutdown(void) +{ + unset_nmi_pm_callback(oprofile_pmdev); + unset_nmi_callback(); + smp_call_function(nmi_cpu_shutdown, NULL, 0, 1); + nmi_cpu_shutdown(0); +} + + +static void nmi_cpu_start(void * dummy) +{ + struct op_msrs const * msrs = &cpu_msrs[smp_processor_id()]; + model->start(msrs); +} + + +static int nmi_start(void) +{ + smp_call_function(nmi_cpu_start, NULL, 0, 1); + nmi_cpu_start(0); + return 0; +} + + +static void nmi_cpu_stop(void * dummy) +{ + struct op_msrs const * msrs = &cpu_msrs[smp_processor_id()]; + model->stop(msrs); +} + + +static void nmi_stop(void) +{ + smp_call_function(nmi_cpu_stop, NULL, 0, 1); + nmi_cpu_stop(0); +} + + +struct op_counter_config counter_config[OP_MAX_COUNTER]; + +static int nmi_create_files(struct super_block * sb, struct dentry * root) +{ + int i; + + for (i = 0; i < model->num_counters; ++i) { + struct dentry * dir; + char buf[2]; + + snprintf(buf, 2, "%d", i); + dir = oprofilefs_mkdir(sb, root, buf); + oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled); + oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event); + oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count); + oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); + oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); + oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); + } + + oprofilefs_create_ulong(sb, root, "kernel_only", &kernel_only); + return 0; +} + + +struct oprofile_operations nmi_ops = { + .create_files = nmi_create_files, + .setup = nmi_setup, + .shutdown = nmi_shutdown, + .start = nmi_start, + .stop = nmi_stop +}; + + +int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu) +{ + __u8 vendor = current_cpu_data.x86_vendor; + __u8 family = current_cpu_data.x86; + __u8 cpu_model = current_cpu_data.x86_model; + + if (!cpu_has_apic) + return 0; + + switch (vendor) { + case X86_VENDOR_AMD: + /* Needs to be at least an Athlon (or hammer in 32bit mode) */ + if (family < 6) + return 0; + model = &op_athlon_spec; + *cpu = OPROFILE_CPU_ATHLON; + break; + + case X86_VENDOR_INTEL: + /* Less than a P6-class processor */ + if (family != 6) + return 0; + + if (cpu_model > 5) { + *cpu = OPROFILE_CPU_PIII; + } else if (cpu_model > 2) { + *cpu = OPROFILE_CPU_PII; + } else { + *cpu = OPROFILE_CPU_PPRO; + } + + model = &op_ppro_spec; + break; + + default: + return 0; + } + + *ops = &nmi_ops; + printk(KERN_INFO "oprofile: using NMI interrupt.\n"); + return 1; +} diff -Nru a/arch/i386/oprofile/op_counter.h b/arch/i386/oprofile/op_counter.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/op_counter.h Tue Oct 15 20:29:25 2002 @@ -0,0 +1,29 @@ +/** + * @file op_counter.h + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef OP_COUNTER_H +#define OP_COUNTER_H + +#define OP_MAX_COUNTER 4 + +/* Per-perfctr configuration as set via + * oprofilefs. + */ +struct op_counter_config { + unsigned long count; + unsigned long enabled; + unsigned long event; + unsigned long kernel; + unsigned long user; + unsigned long unit_mask; +}; + +extern struct op_counter_config counter_config[]; + +#endif /* OP_COUNTER_H */ diff -Nru a/arch/i386/oprofile/op_model_athlon.c b/arch/i386/oprofile/op_model_athlon.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/op_model_athlon.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,149 @@ +/** + * @file op_model_athlon.h + * athlon / K7 model-specific MSR operations + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * @author Philippe Elie + * @author Graydon Hoare + */ + +#include +#include +#include + +#include "op_x86_model.h" +#include "op_counter.h" + +#define NUM_COUNTERS 4 +#define NUM_CONTROLS 4 + +#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters.addrs[(c)], (l), (h));} while (0) +#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters.addrs[(c)], -(unsigned int)(l), -1);} while (0) +#define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) + +#define CTRL_READ(l,h,msrs,c) do {rdmsr(msrs->controls.addrs[(c)], (l), (h));} while (0) +#define CTRL_WRITE(l,h,msrs,c) do {wrmsr(msrs->controls.addrs[(c)], (l), (h));} while (0) +#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) +#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) +#define CTRL_CLEAR(x) (x &= (1<<21)) +#define CTRL_SET_ENABLE(val) (val |= 1<<20) +#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16)) +#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17)) +#define CTRL_SET_UM(val, m) (val |= (m << 8)) +#define CTRL_SET_EVENT(val, e) (val |= e) + +static unsigned long reset_value[NUM_COUNTERS]; + +static void athlon_fill_in_addresses(struct op_msrs * const msrs) +{ + msrs->counters.addrs[0] = MSR_K7_PERFCTR0; + msrs->counters.addrs[1] = MSR_K7_PERFCTR1; + msrs->counters.addrs[2] = MSR_K7_PERFCTR2; + msrs->counters.addrs[3] = MSR_K7_PERFCTR3; + + msrs->controls.addrs[0] = MSR_K7_EVNTSEL0; + msrs->controls.addrs[1] = MSR_K7_EVNTSEL1; + msrs->controls.addrs[2] = MSR_K7_EVNTSEL2; + msrs->controls.addrs[3] = MSR_K7_EVNTSEL3; +} + + +static void athlon_setup_ctrs(struct op_msrs const * const msrs) +{ + unsigned int low, high; + int i; + + /* clear all counters */ + for (i = 0 ; i < NUM_CONTROLS; ++i) { + CTRL_READ(low, high, msrs, i); + CTRL_CLEAR(low); + CTRL_WRITE(low, high, msrs, i); + } + + /* avoid a false detection of ctr overflows in NMI handler */ + for (i = 0; i < NUM_COUNTERS; ++i) { + CTR_WRITE(1, msrs, i); + } + + /* enable active counters */ + for (i = 0; i < NUM_COUNTERS; ++i) { + if (counter_config[i].event) { + reset_value[i] = counter_config[i].count; + + CTR_WRITE(counter_config[i].count, msrs, i); + + CTRL_READ(low, high, msrs, i); + CTRL_CLEAR(low); + CTRL_SET_ENABLE(low); + CTRL_SET_USR(low, counter_config[i].user); + CTRL_SET_KERN(low, counter_config[i].kernel); + CTRL_SET_UM(low, counter_config[i].unit_mask); + CTRL_SET_EVENT(low, counter_config[i].event); + CTRL_WRITE(low, high, msrs, i); + } else { + reset_value[i] = 0; + } + } +} + + +static int athlon_check_ctrs(unsigned int const cpu, + struct op_msrs const * const msrs, + struct pt_regs * const regs) +{ + unsigned int low, high; + int handled = 0; + int i; + for (i = 0 ; i < NUM_COUNTERS; ++i) { + CTR_READ(low, high, msrs, i); + if (CTR_OVERFLOWED(low)) { + oprofile_add_sample(regs->eip, i, cpu); + CTR_WRITE(reset_value[i], msrs, i); + handled = 1; + } + } + return handled; +} + + +static void athlon_start(struct op_msrs const * const msrs) +{ + unsigned int low, high; + int i; + for (i = 0 ; i < NUM_COUNTERS ; ++i) { + if (reset_value[i]) { + CTRL_READ(low, high, msrs, i); + CTRL_SET_ACTIVE(low); + CTRL_WRITE(low, high, msrs, i); + } + } +} + + +static void athlon_stop(struct op_msrs const * const msrs) +{ + unsigned int low,high; + int i; + + /* Subtle: stop on all counters to avoid race with + * setting our pm callback */ + for (i = 0 ; i < NUM_COUNTERS ; ++i) { + CTRL_READ(low, high, msrs, i); + CTRL_SET_INACTIVE(low); + CTRL_WRITE(low, high, msrs, i); + } +} + + +struct op_x86_model_spec const op_athlon_spec = { + .num_counters = NUM_COUNTERS, + .num_controls = NUM_CONTROLS, + .fill_in_addresses = &athlon_fill_in_addresses, + .setup_ctrs = &athlon_setup_ctrs, + .check_ctrs = &athlon_check_ctrs, + .start = &athlon_start, + .stop = &athlon_stop +}; diff -Nru a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/op_model_ppro.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,133 @@ +/** + * @file op_model_ppro.h + * pentium pro / P6 model-specific MSR operations + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * @author Philippe Elie + * @author Graydon Hoare + */ + +#include +#include +#include + +#include "op_x86_model.h" +#include "op_counter.h" + +#define NUM_COUNTERS 2 +#define NUM_CONTROLS 2 + +#define CTR_READ(l,h,msrs,c) do {rdmsr(msrs->counters.addrs[(c)], (l), (h));} while (0) +#define CTR_WRITE(l,msrs,c) do {wrmsr(msrs->counters.addrs[(c)], -(u32)(l), -1);} while (0) +#define CTR_OVERFLOWED(n) (!((n) & (1U<<31))) + +#define CTRL_READ(l,h,msrs,c) do {rdmsr((msrs->controls.addrs[(c)]), (l), (h));} while (0) +#define CTRL_WRITE(l,h,msrs,c) do {wrmsr((msrs->controls.addrs[(c)]), (l), (h));} while (0) +#define CTRL_SET_ACTIVE(n) (n |= (1<<22)) +#define CTRL_SET_INACTIVE(n) (n &= ~(1<<22)) +#define CTRL_CLEAR(x) (x &= (1<<21)) +#define CTRL_SET_ENABLE(val) (val |= 1<<20) +#define CTRL_SET_USR(val,u) (val |= ((u & 1) << 16)) +#define CTRL_SET_KERN(val,k) (val |= ((k & 1) << 17)) +#define CTRL_SET_UM(val, m) (val |= (m << 8)) +#define CTRL_SET_EVENT(val, e) (val |= e) + +static unsigned long reset_value[NUM_COUNTERS]; + +static void ppro_fill_in_addresses(struct op_msrs * const msrs) +{ + msrs->counters.addrs[0] = MSR_P6_PERFCTR0; + msrs->counters.addrs[1] = MSR_P6_PERFCTR1; + + msrs->controls.addrs[0] = MSR_P6_EVNTSEL0; + msrs->controls.addrs[1] = MSR_P6_EVNTSEL1; +} + + +static void ppro_setup_ctrs(struct op_msrs const * const msrs) +{ + unsigned int low, high; + int i; + + /* clear all counters */ + for (i = 0 ; i < NUM_CONTROLS; ++i) { + CTRL_READ(low, high, msrs, i); + CTRL_CLEAR(low); + CTRL_WRITE(low, high, msrs, i); + } + + /* avoid a false detection of ctr overflows in NMI handler */ + for (i = 0; i < NUM_COUNTERS; ++i) { + CTR_WRITE(1, msrs, i); + } + + /* enable active counters */ + for (i = 0; i < NUM_COUNTERS; ++i) { + if (counter_config[i].event) { + reset_value[i] = counter_config[i].count; + + CTR_WRITE(counter_config[i].count, msrs, i); + + CTRL_READ(low, high, msrs, i); + CTRL_CLEAR(low); + CTRL_SET_ENABLE(low); + CTRL_SET_USR(low, counter_config[i].user); + CTRL_SET_KERN(low, counter_config[i].kernel); + CTRL_SET_UM(low, counter_config[i].unit_mask); + CTRL_SET_EVENT(low, counter_config[i].event); + CTRL_WRITE(low, high, msrs, i); + } + } +} + + +static int ppro_check_ctrs(unsigned int const cpu, + struct op_msrs const * const msrs, + struct pt_regs * const regs) +{ + unsigned int low, high; + int i; + int handled = 0; + + for (i = 0 ; i < NUM_COUNTERS; ++i) { + CTR_READ(low, high, msrs, i); + if (CTR_OVERFLOWED(low)) { + oprofile_add_sample(regs->eip, i, cpu); + CTR_WRITE(reset_value[i], msrs, i); + handled = 1; + } + } + return handled; +} + + +static void ppro_start(struct op_msrs const * const msrs) +{ + unsigned int low,high; + CTRL_READ(low, high, msrs, 0); + CTRL_SET_ACTIVE(low); + CTRL_WRITE(low, high, msrs, 0); +} + + +static void ppro_stop(struct op_msrs const * const msrs) +{ + unsigned int low,high; + CTRL_READ(low, high, msrs, 0); + CTRL_SET_INACTIVE(low); + CTRL_WRITE(low, high, msrs, 0); +} + + +struct op_x86_model_spec const op_ppro_spec = { + .num_counters = NUM_COUNTERS, + .num_controls = NUM_CONTROLS, + .fill_in_addresses = &ppro_fill_in_addresses, + .setup_ctrs = &ppro_setup_ctrs, + .check_ctrs = &ppro_check_ctrs, + .start = &ppro_start, + .stop = &ppro_stop +}; diff -Nru a/arch/i386/oprofile/op_x86_model.h b/arch/i386/oprofile/op_x86_model.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/op_x86_model.h Tue Oct 15 20:29:25 2002 @@ -0,0 +1,52 @@ +/** + * @file op_x86_model.h + * interface to x86 model-specific MSR operations + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author Graydon Hoare + */ + +#ifndef OP_X86_MODEL_H +#define OP_X86_MODEL_H + +/* will need re-working for Pentium IV */ +#define MAX_MSR 4 + +struct op_saved_msr { + unsigned int high; + unsigned int low; +}; + +struct op_msr_group { + unsigned int addrs[MAX_MSR]; + struct op_saved_msr saved[MAX_MSR]; +}; + +struct op_msrs { + struct op_msr_group counters; + struct op_msr_group controls; +}; + +struct pt_regs; + +/* The model vtable abstracts the differences between + * various x86 CPU model's perfctr support. + */ +struct op_x86_model_spec { + unsigned int const num_counters; + unsigned int const num_controls; + void (*fill_in_addresses)(struct op_msrs * const msrs); + void (*setup_ctrs)(struct op_msrs const * const msrs); + int (*check_ctrs)(unsigned int const cpu, + struct op_msrs const * const msrs, + struct pt_regs * const regs); + void (*start)(struct op_msrs const * const msrs); + void (*stop)(struct op_msrs const * const msrs); +}; + +extern struct op_x86_model_spec const op_ppro_spec; +extern struct op_x86_model_spec const op_athlon_spec; + +#endif /* OP_X86_MODEL_H */ diff -Nru a/arch/i386/oprofile/timer_int.c b/arch/i386/oprofile/timer_int.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/oprofile/timer_int.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,57 @@ +/** + * @file timer_int.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include +#include +#include + +#include "op_counter.h" + +static int timer_notify(struct notifier_block * self, unsigned long val, void * data) +{ + struct pt_regs * regs = (struct pt_regs *)data; + int cpu = smp_processor_id(); + + oprofile_add_sample(regs->eip, 0, cpu); + return 0; +} + + +static struct notifier_block timer_notifier = { + .notifier_call = timer_notify, +}; + + +static int timer_start(void) +{ + return register_profile_notifier(&timer_notifier); +} + + +static void timer_stop(void) +{ + unregister_profile_notifier(&timer_notifier); +} + + +static struct oprofile_operations timer_ops = { + .start = timer_start, + .stop = timer_stop +}; + + +void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu) +{ + *ops = &timer_ops; + *cpu = OPROFILE_CPU_TIMER; + printk(KERN_INFO "oprofile: using timer interrupt.\n"); +} diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c --- a/arch/ia64/ia32/sys_ia32.c Tue Oct 15 20:29:17 2002 +++ b/arch/ia64/ia32/sys_ia32.c Tue Oct 15 20:29:17 2002 @@ -1763,7 +1763,6 @@ struct msghdr msg_sys; unsigned long cmsg_ptr; int err, iov_size, total_len, len; - struct scm_cookie scm; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; @@ -1811,20 +1810,35 @@ if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - + /* XXX This code needs massive updating... -DaveM */ lock_kernel(); { - err = sock->ops->recvmsg(sock, &msg_sys, total_len, flags, &scm); + struct sock_iocb *si; + struct kiocb iocb; + + init_sync_kiocb(&iocb, NULL); + si = kiocb_to_siocb(&iocb); + si->sock = sock; + si->scm = &si->async_scm; + si->msg = &msg_sys; + si->size = total_len; + si->flags = flags; + memset(si->scm, 0, sizeof(*si->scm)); + + err = sock->ops->recvmsg(&iocb, sock, &msg_sys, total_len, + flags, si->scm); + if (-EIOCBQUEUED == err) + err = wait_on_sync_kiocb(&iocb); + if (err < 0) goto out_unlock_freeiov; len = err; if (!msg_sys.msg_control) { - if (sock->passcred || scm.fp) + if (sock->passcred || si->scm->fp) msg_sys.msg_flags |= MSG_CTRUNC; - if (scm.fp) - __scm_destroy(&scm); + if (si->scm->fp) + __scm_destroy(si->scm); } else { /* * If recvmsg processing itself placed some control messages into @@ -1837,9 +1851,10 @@ /* Wheee... */ if (sock->passcred) put_cmsg32(&msg_sys, SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), &scm.creds); - if (scm.fp != NULL) - scm_detach_fds32(&msg_sys, &scm); + sizeof(si->scm->creds), + &si->scm->creds); + if (si->scm->fp != NULL) + scm_detach_fds32(&msg_sys, si->scm); } } unlock_kernel(); diff -Nru a/arch/m68k/atari/stram.c b/arch/m68k/atari/stram.c --- a/arch/m68k/atari/stram.c Tue Oct 15 20:29:19 2002 +++ b/arch/m68k/atari/stram.c Tue Oct 15 20:29:19 2002 @@ -1021,8 +1021,6 @@ printk( KERN_NOTICE "Only kernel can open ST-RAM device\n" ); return( -EPERM ); } - if (MINOR(inode->i_rdev) != STRAM_MINOR) - return( -ENXIO ); if (refcnt) return( -EBUSY ); ++refcnt; @@ -1057,7 +1055,7 @@ if (!max_swap_size) /* swapping not enabled */ return -ENXIO; - stram_disk = alloc_disk(); + stram_disk = alloc_disk(1); if (!stram_disk) return -ENOMEM; @@ -1070,7 +1068,6 @@ blk_init_queue(BLK_DEFAULT_QUEUE(STRAM_MAJOR), do_stram_request); stram_disk->major = STRAM_MAJOR; stram_disk->first_minor = STRAM_MINOR; - stram_disk->minor_shift = 0; stram_disk->fops = &stram_fops; sprintf(stram_disk->disk_name, "stram"); set_capacity(stram_disk, (swap_end - swap_start)/512); diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c --- a/arch/ppc64/kernel/sys_ppc32.c Tue Oct 15 20:29:19 2002 +++ b/arch/ppc64/kernel/sys_ppc32.c Tue Oct 15 20:29:19 2002 @@ -3320,20 +3320,33 @@ sock = sockfd_lookup(fd, &err); if (sock != NULL) { - struct scm_cookie scm; + struct sock_iocb *si; + struct kiocb iocb; if (sock->file->f_flags & O_NONBLOCK) user_flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - err = sock->ops->recvmsg(sock, &kern_msg, total_len, - user_flags, &scm); + + init_sync_kiocb(&iocb, NULL); + si = kiocb_to_siocb(&iocb); + si->sock = sock; + si->scm = &si->async_scm; + si->msg = &kern_msg; + si->size = total_len; + si->flags = user_flags; + memset(si->scm, 0, sizeof(*si->scm)); + + err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len, + user_flags, si->scm); + if (-EIOCBQUEUED == err) + err = wait_on_sync_kiocb(&iocb); + if(err >= 0) { len = err; if(!kern_msg.msg_control) { - if(sock->passcred || scm.fp) + if(sock->passcred || si->scm->fp) kern_msg.msg_flags |= MSG_CTRUNC; - if(scm.fp) - __scm_destroy(&scm); + if(si->scm->fp) + __scm_destroy(si->scm); } else { /* If recvmsg processing itself placed some * control messages into user space, it's is @@ -3347,9 +3360,10 @@ if(sock->passcred) put_cmsg32(&kern_msg, SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), &scm.creds); - if(scm.fp != NULL) - scm_detach_fds32(&kern_msg, &scm); + sizeof(si->scm->creds), + &si->scm->creds); + if(si->scm->fp != NULL) + scm_detach_fds32(&kern_msg, si->scm); } } sockfd_put(sock); diff -Nru a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c --- a/arch/s390x/kernel/linux32.c Tue Oct 15 20:29:12 2002 +++ b/arch/s390x/kernel/linux32.c Tue Oct 15 20:29:12 2002 @@ -2596,20 +2596,33 @@ sock = sockfd_lookup(fd, &err); if (sock != NULL) { - struct scm_cookie scm; + struct sock_iocb *si; + struct kiocb iocb; if (sock->file->f_flags & O_NONBLOCK) user_flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - err = sock->ops->recvmsg(sock, &kern_msg, total_len, - user_flags, &scm); + + init_sync_kiocb(&iocb, NULL); + si = kiocb_to_siocb(&iocb); + si->sock = sock; + si->scm = &si->async_scm; + si->msg = &kern_msg; + si->size = total_len; + si->flags = user_flags; + memset(si->scm, 0, sizeof(*si->scm)); + + err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len, + user_flags, si->scm); + if (-EIOCBQUEUED == err) + err = wait_on_sync_kiocb(&iocb); + if(err >= 0) { len = err; if(!kern_msg.msg_control) { - if(sock->passcred || scm.fp) + if(sock->passcred || si->scm->fp) kern_msg.msg_flags |= MSG_CTRUNC; - if(scm.fp) - __scm_destroy(&scm); + if(si->scm->fp) + __scm_destroy(si->scm); } else { /* If recvmsg processing itself placed some * control messages into user space, it's is @@ -2623,9 +2636,10 @@ if(sock->passcred) put_cmsg32(&kern_msg, SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), &scm.creds); - if(scm.fp != NULL) - scm_detach_fds32(&kern_msg, &scm); + sizeof(si->scm->creds), + &si->scm->creds); + if(si->scm->fp != NULL) + scm_detach_fds32(&kern_msg, si->scm); } } sockfd_put(sock); @@ -2746,6 +2760,8 @@ struct msghdr msg_sys; unsigned long cmsg_ptr; int err, iov_size, total_len, len; + struct sock_iocb *si; + struct kiocb iocb; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; @@ -2753,7 +2769,6 @@ /* user mode address pointers */ struct sockaddr *uaddr; int *uaddr_len; - struct scm_cookie scm; err=-EFAULT; if (msghdr_from_user32_to_kern(&msg_sys, msg)) @@ -2793,9 +2808,20 @@ if (sock->file->f_flags & O_NONBLOCK) flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - err = sock->ops->recvmsg(sock, &msg_sys, total_len, - flags, &scm); + + init_sync_kiocb(&iocb, NULL); + si = kiocb_to_siocb(&iocb); + si->sock = sock; + si->scm = &si->async_scm; + si->msg = &msg_sys; + si->size = total_len; + si->flags = flags; + memset(si->scm, 0, sizeof(*si->scm)); + + err = sock->ops->recvmsg(&iocb, sock, &msg_sys, total_len, + flags, si->scm); + if (-EIOCBQUEUED == err) + err = wait_on_sync_kiocb(&iocb); if (err < 0) goto out_freeiov; len = err; @@ -2808,10 +2834,10 @@ goto out_freeiov; } if(!msg_sys.msg_control) { - if(sock->passcred || scm.fp) + if(sock->passcred || si->scm->fp) msg_sys.msg_flags |= MSG_CTRUNC; - if(scm.fp) - __scm_destroy(&scm); + if(si->scm->fp) + __scm_destroy(si->scm); } else { /* If recvmsg processing itself placed some * control messages into user space, it's is @@ -2824,9 +2850,9 @@ if(sock->passcred) put_cmsg32(&msg_sys, SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), &scm.creds); - if(scm.fp != NULL) - scm_detach_fds32(&msg_sys, &scm); + sizeof(si->scm->creds), &si->scm->creds); + if(si->scm->fp != NULL) + scm_detach_fds32(&msg_sys, si->scm); } out_freeiov: diff -Nru a/arch/sh/kernel/mach_7751se.c b/arch/sh/kernel/mach_7751se.c --- a/arch/sh/kernel/mach_7751se.c Tue Oct 15 20:29:17 2002 +++ b/arch/sh/kernel/mach_7751se.c Tue Oct 15 20:29:17 2002 @@ -27,52 +27,52 @@ */ struct sh_machine_vector mv_7751se __initmv = { - mv_name: "7751 SolutionEngine", + .mv_name = "7751 SolutionEngine", - mv_nr_irqs: 72, + .mv_nr_irqs = 72, - mv_inb: sh7751se_inb, - mv_inw: sh7751se_inw, - mv_inl: sh7751se_inl, - mv_outb: sh7751se_outb, - mv_outw: sh7751se_outw, - mv_outl: sh7751se_outl, - - mv_inb_p: sh7751se_inb_p, - mv_inw_p: sh7751se_inw, - mv_inl_p: sh7751se_inl, - mv_outb_p: sh7751se_outb_p, - mv_outw_p: sh7751se_outw, - mv_outl_p: sh7751se_outl, - - mv_insb: sh7751se_insb, - mv_insw: sh7751se_insw, - mv_insl: sh7751se_insl, - mv_outsb: sh7751se_outsb, - mv_outsw: sh7751se_outsw, - mv_outsl: sh7751se_outsl, - - mv_readb: sh7751se_readb, - mv_readw: sh7751se_readw, - mv_readl: sh7751se_readl, - mv_writeb: sh7751se_writeb, - mv_writew: sh7751se_writew, - mv_writel: sh7751se_writel, + .mv_inb = sh7751se_inb, + .mv_inw = sh7751se_inw, + .mv_inl = sh7751se_inl, + .mv_outb = sh7751se_outb, + .mv_outw = sh7751se_outw, + .mv_outl = sh7751se_outl, + + .mv_inb_p = sh7751se_inb_p, + .mv_inw_p = sh7751se_inw, + .mv_inl_p = sh7751se_inl, + .mv_outb_p = sh7751se_outb_p, + .mv_outw_p = sh7751se_outw, + .mv_outl_p = sh7751se_outl, + + .mv_insb = sh7751se_insb, + .mv_insw = sh7751se_insw, + .mv_insl = sh7751se_insl, + .mv_outsb = sh7751se_outsb, + .mv_outsw = sh7751se_outsw, + .mv_outsl = sh7751se_outsl, + + .mv_readb = sh7751se_readb, + .mv_readw = sh7751se_readw, + .mv_readl = sh7751se_readl, + .mv_writeb = sh7751se_writeb, + .mv_writew = sh7751se_writew, + .mv_writel = sh7751se_writel, - mv_ioremap: generic_ioremap, - mv_iounmap: generic_iounmap, + .mv_ioremap = generic_ioremap, + .mv_iounmap = generic_iounmap, - mv_isa_port2addr: sh7751se_isa_port2addr, + .mv_isa_port2addr = sh7751se_isa_port2addr, - mv_init_arch: setup_7751se, - mv_init_irq: init_7751se_IRQ, + .mv_init_arch = setup_7751se, + .mv_init_irq = init_7751se_IRQ, #ifdef CONFIG_HEARTBEAT - mv_heartbeat: heartbeat_7751se, + .mv_heartbeat = heartbeat_7751se, #endif - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, - mv_hw_7751se: 1, + .mv_hw_7751se = 1, }; ALIAS_MV(7751se) diff -Nru a/arch/sh/kernel/mach_adx.c b/arch/sh/kernel/mach_adx.c --- a/arch/sh/kernel/mach_adx.c Tue Oct 15 20:29:17 2002 +++ b/arch/sh/kernel/mach_adx.c Tue Oct 15 20:29:17 2002 @@ -25,49 +25,49 @@ */ struct sh_machine_vector mv_adx __initmv = { - mv_name: "A&D_ADX", + .mv_name = "A&D_ADX", - mv_nr_irqs: 48, + .mv_nr_irqs = 48, - mv_inb: adx_inb, - mv_inw: adx_inw, - mv_inl: adx_inl, - mv_outb: adx_outb, - mv_outw: adx_outw, - mv_outl: adx_outl, - - mv_inb_p: adx_inb_p, - mv_inw_p: adx_inw, - mv_inl_p: adx_inl, - mv_outb_p: adx_outb_p, - mv_outw_p: adx_outw, - mv_outl_p: adx_outl, - - mv_insb: adx_insb, - mv_insw: adx_insw, - mv_insl: adx_insl, - mv_outsb: adx_outsb, - mv_outsw: adx_outsw, - mv_outsl: adx_outsl, - - mv_readb: adx_readb, - mv_readw: adx_readw, - mv_readl: adx_readl, - mv_writeb: adx_writeb, - mv_writew: adx_writew, - mv_writel: adx_writel, - - mv_ioremap: adx_ioremap, - mv_iounmap: adx_iounmap, - - mv_isa_port2addr: adx_isa_port2addr, + .mv_inb = adx_inb, + .mv_inw = adx_inw, + .mv_inl = adx_inl, + .mv_outb = adx_outb, + .mv_outw = adx_outw, + .mv_outl = adx_outl, + + .mv_inb_p = adx_inb_p, + .mv_inw_p = adx_inw, + .mv_inl_p = adx_inl, + .mv_outb_p = adx_outb_p, + .mv_outw_p = adx_outw, + .mv_outl_p = adx_outl, + + .mv_insb = adx_insb, + .mv_insw = adx_insw, + .mv_insl = adx_insl, + .mv_outsb = adx_outsb, + .mv_outsw = adx_outsw, + .mv_outsl = adx_outsl, + + .mv_readb = adx_readb, + .mv_readw = adx_readw, + .mv_readl = adx_readl, + .mv_writeb = adx_writeb, + .mv_writew = adx_writew, + .mv_writel = adx_writel, + + .mv_ioremap = adx_ioremap, + .mv_iounmap = adx_iounmap, + + .mv_isa_port2addr = adx_isa_port2addr, - mv_init_arch: setup_adx, - mv_init_irq: init_adx_IRQ, + .mv_init_arch = setup_adx, + .mv_init_irq = init_adx_IRQ, - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, - mv_hw_adx: 1, + .mv_hw_adx = 1, }; ALIAS_MV(adx) diff -Nru a/arch/sh/kernel/mach_bigsur.c b/arch/sh/kernel/mach_bigsur.c --- a/arch/sh/kernel/mach_bigsur.c Tue Oct 15 20:29:19 2002 +++ b/arch/sh/kernel/mach_bigsur.c Tue Oct 15 20:29:19 2002 @@ -29,49 +29,49 @@ extern void init_bigsur_IRQ(void); struct sh_machine_vector mv_bigsur __initmv = { - mv_name: "Big Sur", - mv_nr_irqs: NR_IRQS, // Defined in - mv_inb: bigsur_inb, - mv_inw: bigsur_inw, - mv_inl: bigsur_inl, - mv_outb: bigsur_outb, - mv_outw: bigsur_outw, - mv_outl: bigsur_outl, - - mv_inb_p: bigsur_inb_p, - mv_inw_p: bigsur_inw, - mv_inl_p: bigsur_inl, - mv_outb_p: bigsur_outb_p, - mv_outw_p: bigsur_outw, - mv_outl_p: bigsur_outl, - - mv_insb: bigsur_insb, - mv_insw: bigsur_insw, - mv_insl: bigsur_insl, - mv_outsb: bigsur_outsb, - mv_outsw: bigsur_outsw, - mv_outsl: bigsur_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, + .mv_name = "Big Sur", + .mv_nr_irqs = NR_IRQS, // Defined in + .mv_inb = bigsur_inb, + .mv_inw = bigsur_inw, + .mv_inl = bigsur_inl, + .mv_outb = bigsur_outb, + .mv_outw = bigsur_outw, + .mv_outl = bigsur_outl, + + .mv_inb_p = bigsur_inb_p, + .mv_inw_p = bigsur_inw, + .mv_inl_p = bigsur_inl, + .mv_outb_p = bigsur_outb_p, + .mv_outw_p = bigsur_outw, + .mv_outl_p = bigsur_outl, + + .mv_insb = bigsur_insb, + .mv_insw = bigsur_insw, + .mv_insl = bigsur_insl, + .mv_outsb = bigsur_outsb, + .mv_outsw = bigsur_outsw, + .mv_outsl = bigsur_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, - mv_ioremap: generic_ioremap, - mv_iounmap: generic_iounmap, + .mv_ioremap = generic_ioremap, + .mv_iounmap = generic_iounmap, - mv_isa_port2addr: bigsur_isa_port2addr, - mv_irq_demux: bigsur_irq_demux, + .mv_isa_port2addr = bigsur_isa_port2addr, + .mv_irq_demux = bigsur_irq_demux, - mv_init_arch: setup_bigsur, - mv_init_irq: init_bigsur_IRQ, + .mv_init_arch = setup_bigsur, + .mv_init_irq = init_bigsur_IRQ, #ifdef CONFIG_HEARTBEAT - mv_heartbeat: heartbeat_bigsur, + .mv_heartbeat = heartbeat_bigsur, #endif - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, }; ALIAS_MV(bigsur) diff -Nru a/arch/sh/kernel/mach_cat68701.c b/arch/sh/kernel/mach_cat68701.c --- a/arch/sh/kernel/mach_cat68701.c Tue Oct 15 20:29:22 2002 +++ b/arch/sh/kernel/mach_cat68701.c Tue Oct 15 20:29:22 2002 @@ -23,50 +23,50 @@ */ struct sh_machine_vector mv_cat68701 __initmv = { - mv_name: "CAT-68701", - mv_nr_irqs: 32, - mv_inb: cat68701_inb, - mv_inw: cat68701_inw, - mv_inl: cat68701_inl, - mv_outb: cat68701_outb, - mv_outw: cat68701_outw, - mv_outl: cat68701_outl, - - mv_inb_p: cat68701_inb_p, - mv_inw_p: cat68701_inw, - mv_inl_p: cat68701_inl, - mv_outb_p: cat68701_outb_p, - mv_outw_p: cat68701_outw, - mv_outl_p: cat68701_outl, - - mv_insb: cat68701_insb, - mv_insw: cat68701_insw, - mv_insl: cat68701_insl, - mv_outsb: cat68701_outsb, - mv_outsw: cat68701_outsw, - mv_outsl: cat68701_outsl, - - mv_readb: cat68701_readb, - mv_readw: cat68701_readw, - mv_readl: cat68701_readl, - mv_writeb: cat68701_writeb, - mv_writew: cat68701_writew, - mv_writel: cat68701_writel, + .mv_name = "CAT-68701", + .mv_nr_irqs = 32, + .mv_inb = cat68701_inb, + .mv_inw = cat68701_inw, + .mv_inl = cat68701_inl, + .mv_outb = cat68701_outb, + .mv_outw = cat68701_outw, + .mv_outl = cat68701_outl, + + .mv_inb_p = cat68701_inb_p, + .mv_inw_p = cat68701_inw, + .mv_inl_p = cat68701_inl, + .mv_outb_p = cat68701_outb_p, + .mv_outw_p = cat68701_outw, + .mv_outl_p = cat68701_outl, + + .mv_insb = cat68701_insb, + .mv_insw = cat68701_insw, + .mv_insl = cat68701_insl, + .mv_outsb = cat68701_outsb, + .mv_outsw = cat68701_outsw, + .mv_outsl = cat68701_outsl, + + .mv_readb = cat68701_readb, + .mv_readw = cat68701_readw, + .mv_readl = cat68701_readl, + .mv_writeb = cat68701_writeb, + .mv_writew = cat68701_writew, + .mv_writel = cat68701_writel, - mv_ioremap: cat68701_ioremap, - mv_iounmap: cat68701_iounmap, + .mv_ioremap = cat68701_ioremap, + .mv_iounmap = cat68701_iounmap, - mv_isa_port2addr: cat68701_isa_port2addr, - mv_irq_demux: cat68701_irq_demux, + .mv_isa_port2addr = cat68701_isa_port2addr, + .mv_irq_demux = cat68701_irq_demux, - mv_init_arch: setup_cat68701, - mv_init_irq: init_cat68701_IRQ, + .mv_init_arch = setup_cat68701, + .mv_init_irq = init_cat68701_IRQ, #ifdef CONFIG_HEARTBEAT - mv_heartbeat: heartbeat_cat68701, + .mv_heartbeat = heartbeat_cat68701, #endif - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, }; ALIAS_MV(cat68701) diff -Nru a/arch/sh/kernel/mach_dc.c b/arch/sh/kernel/mach_dc.c --- a/arch/sh/kernel/mach_dc.c Tue Oct 15 20:29:12 2002 +++ b/arch/sh/kernel/mach_dc.c Tue Oct 15 20:29:12 2002 @@ -26,48 +26,48 @@ */ struct sh_machine_vector mv_dreamcast __initmv = { - mv_name: "dreamcast", + .mv_name = "dreamcast", - mv_nr_irqs: NR_IRQS, + .mv_nr_irqs = NR_IRQS, - mv_inb: generic_inb, - mv_inw: generic_inw, - mv_inl: generic_inl, - mv_outb: generic_outb, - mv_outw: generic_outw, - mv_outl: generic_outl, - - mv_inb_p: generic_inb_p, - mv_inw_p: generic_inw, - mv_inl_p: generic_inl, - mv_outb_p: generic_outb_p, - mv_outw_p: generic_outw, - mv_outl_p: generic_outl, - - mv_insb: generic_insb, - mv_insw: generic_insw, - mv_insl: generic_insl, - mv_outsb: generic_outsb, - mv_outsw: generic_outsw, - mv_outsl: generic_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, - - mv_ioremap: generic_ioremap, - mv_iounmap: generic_iounmap, - - mv_init_arch: setup_dreamcast, - mv_isa_port2addr: dreamcast_isa_port2addr, - mv_irq_demux: systemasic_irq_demux, + .mv_inb = generic_inb, + .mv_inw = generic_inw, + .mv_inl = generic_inl, + .mv_outb = generic_outb, + .mv_outw = generic_outw, + .mv_outl = generic_outl, + + .mv_inb_p = generic_inb_p, + .mv_inw_p = generic_inw, + .mv_inl_p = generic_inl, + .mv_outb_p = generic_outb_p, + .mv_outw_p = generic_outw, + .mv_outl_p = generic_outl, + + .mv_insb = generic_insb, + .mv_insw = generic_insw, + .mv_insl = generic_insl, + .mv_outsb = generic_outsb, + .mv_outsw = generic_outsw, + .mv_outsl = generic_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, + + .mv_ioremap = generic_ioremap, + .mv_iounmap = generic_iounmap, + + .mv_init_arch = setup_dreamcast, + .mv_isa_port2addr = dreamcast_isa_port2addr, + .mv_irq_demux = systemasic_irq_demux, - mv_rtc_gettimeofday: aica_rtc_gettimeofday, - mv_rtc_settimeofday: aica_rtc_settimeofday, + .mv_rtc_gettimeofday = aica_rtc_gettimeofday, + .mv_rtc_settimeofday = aica_rtc_settimeofday, - mv_hw_dreamcast: 1, + .mv_hw_dreamcast = 1, }; ALIAS_MV(dreamcast) diff -Nru a/arch/sh/kernel/mach_dmida.c b/arch/sh/kernel/mach_dmida.c --- a/arch/sh/kernel/mach_dmida.c Tue Oct 15 20:29:12 2002 +++ b/arch/sh/kernel/mach_dmida.c Tue Oct 15 20:29:12 2002 @@ -30,44 +30,44 @@ */ struct sh_machine_vector mv_dmida __initmv = { - mv_name: "DMIDA", + .mv_name = "DMIDA", - mv_nr_irqs: HD64465_IRQ_BASE+HD64465_IRQ_NUM, + .mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM, - mv_inb: hd64465_inb, - mv_inw: hd64465_inw, - mv_inl: hd64465_inl, - mv_outb: hd64465_outb, - mv_outw: hd64465_outw, - mv_outl: hd64465_outl, - - mv_inb_p: hd64465_inb_p, - mv_inw_p: hd64465_inw, - mv_inl_p: hd64465_inl, - mv_outb_p: hd64465_outb_p, - mv_outw_p: hd64465_outw, - mv_outl_p: hd64465_outl, - - mv_insb: hd64465_insb, - mv_insw: hd64465_insw, - mv_insl: hd64465_insl, - mv_outsb: hd64465_outsb, - mv_outsw: hd64465_outsw, - mv_outsl: hd64465_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, + .mv_inb = hd64465_inb, + .mv_inw = hd64465_inw, + .mv_inl = hd64465_inl, + .mv_outb = hd64465_outb, + .mv_outw = hd64465_outw, + .mv_outl = hd64465_outl, + + .mv_inb_p = hd64465_inb_p, + .mv_inw_p = hd64465_inw, + .mv_inl_p = hd64465_inl, + .mv_outb_p = hd64465_outb_p, + .mv_outw_p = hd64465_outw, + .mv_outl_p = hd64465_outl, + + .mv_insb = hd64465_insb, + .mv_insw = hd64465_insw, + .mv_insl = hd64465_insl, + .mv_outsb = hd64465_outsb, + .mv_outsw = hd64465_outsw, + .mv_outsl = hd64465_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, - mv_irq_demux: hd64465_irq_demux, + .mv_irq_demux = hd64465_irq_demux, - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, - mv_hw_hd64465: 1, + .mv_hw_hd64465 = 1, }; ALIAS_MV(dmida) diff -Nru a/arch/sh/kernel/mach_ec3104.c b/arch/sh/kernel/mach_ec3104.c --- a/arch/sh/kernel/mach_ec3104.c Tue Oct 15 20:29:20 2002 +++ b/arch/sh/kernel/mach_ec3104.c Tue Oct 15 20:29:20 2002 @@ -28,42 +28,42 @@ */ struct sh_machine_vector mv_ec3104 __initmv = { - mv_name: "EC3104", + .mv_name = "EC3104", - mv_nr_irqs: 96, + .mv_nr_irqs = 96, - mv_inb: ec3104_inb, - mv_inw: ec3104_inw, - mv_inl: ec3104_inl, - mv_outb: ec3104_outb, - mv_outw: ec3104_outw, - mv_outl: ec3104_outl, - - mv_inb_p: generic_inb_p, - mv_inw_p: generic_inw, - mv_inl_p: generic_inl, - mv_outb_p: generic_outb_p, - mv_outw_p: generic_outw, - mv_outl_p: generic_outl, - - mv_insb: generic_insb, - mv_insw: generic_insw, - mv_insl: generic_insl, - mv_outsb: generic_outsb, - mv_outsw: generic_outsw, - mv_outsl: generic_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, + .mv_inb = ec3104_inb, + .mv_inw = ec3104_inw, + .mv_inl = ec3104_inl, + .mv_outb = ec3104_outb, + .mv_outw = ec3104_outw, + .mv_outl = ec3104_outl, + + .mv_inb_p = generic_inb_p, + .mv_inw_p = generic_inw, + .mv_inl_p = generic_inl, + .mv_outb_p = generic_outb_p, + .mv_outw_p = generic_outw, + .mv_outl_p = generic_outl, + + .mv_insb = generic_insb, + .mv_insw = generic_insw, + .mv_insl = generic_insl, + .mv_outsb = generic_outsb, + .mv_outsw = generic_outsw, + .mv_outsl = generic_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, - mv_irq_demux: ec3104_irq_demux, + .mv_irq_demux = ec3104_irq_demux, - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, }; ALIAS_MV(ec3104) diff -Nru a/arch/sh/kernel/mach_hp600.c b/arch/sh/kernel/mach_hp600.c --- a/arch/sh/kernel/mach_hp600.c Tue Oct 15 20:29:17 2002 +++ b/arch/sh/kernel/mach_hp600.c Tue Oct 15 20:29:17 2002 @@ -24,135 +24,135 @@ */ struct sh_machine_vector mv_hp620 __initmv = { - mv_name: "hp620", + .mv_name = "hp620", - mv_nr_irqs: HD64461_IRQBASE+HD64461_IRQ_NUM, + .mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM, - mv_inb: hd64461_inb, - mv_inw: hd64461_inw, - mv_inl: hd64461_inl, - mv_outb: hd64461_outb, - mv_outw: hd64461_outw, - mv_outl: hd64461_outl, - - mv_inb_p: hd64461_inb_p, - mv_inw_p: hd64461_inw, - mv_inl_p: hd64461_inl, - mv_outb_p: hd64461_outb_p, - mv_outw_p: hd64461_outw, - mv_outl_p: hd64461_outl, - - mv_insb: hd64461_insb, - mv_insw: hd64461_insw, - mv_insl: hd64461_insl, - mv_outsb: hd64461_outsb, - mv_outsw: hd64461_outsw, - mv_outsl: hd64461_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, - - mv_irq_demux: hd64461_irq_demux, - - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, - - mv_hw_hp600: 1, - mv_hw_hp620: 1, - mv_hw_hd64461: 1, + .mv_inb = hd64461_inb, + .mv_inw = hd64461_inw, + .mv_inl = hd64461_inl, + .mv_outb = hd64461_outb, + .mv_outw = hd64461_outw, + .mv_outl = hd64461_outl, + + .mv_inb_p = hd64461_inb_p, + .mv_inw_p = hd64461_inw, + .mv_inl_p = hd64461_inl, + .mv_outb_p = hd64461_outb_p, + .mv_outw_p = hd64461_outw, + .mv_outl_p = hd64461_outl, + + .mv_insb = hd64461_insb, + .mv_insw = hd64461_insw, + .mv_insl = hd64461_insl, + .mv_outsb = hd64461_outsb, + .mv_outsw = hd64461_outsw, + .mv_outsl = hd64461_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, + + .mv_irq_demux = hd64461_irq_demux, + + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, + + .mv_hw_hp600 = 1, + .mv_hw_hp620 = 1, + .mv_hw_hd64461 = 1, }; ALIAS_MV(hp620) struct sh_machine_vector mv_hp680 __initmv = { - mv_name: "hp680", + .mv_name = "hp680", - mv_nr_irqs: HD64461_IRQBASE+HD64461_IRQ_NUM, + .mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM, - mv_inb: hd64461_inb, - mv_inw: hd64461_inw, - mv_inl: hd64461_inl, - mv_outb: hd64461_outb, - mv_outw: hd64461_outw, - mv_outl: hd64461_outl, - - mv_inb_p: hd64461_inb_p, - mv_inw_p: hd64461_inw, - mv_inl_p: hd64461_inl, - mv_outb_p: hd64461_outb_p, - mv_outw_p: hd64461_outw, - mv_outl_p: hd64461_outl, - - mv_insb: hd64461_insb, - mv_insw: hd64461_insw, - mv_insl: hd64461_insl, - mv_outsb: hd64461_outsb, - mv_outsw: hd64461_outsw, - mv_outsl: hd64461_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, - - mv_irq_demux: hd64461_irq_demux, - - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, - - mv_hw_hp600: 1, - mv_hw_hp680: 1, - mv_hw_hd64461: 1, + .mv_inb = hd64461_inb, + .mv_inw = hd64461_inw, + .mv_inl = hd64461_inl, + .mv_outb = hd64461_outb, + .mv_outw = hd64461_outw, + .mv_outl = hd64461_outl, + + .mv_inb_p = hd64461_inb_p, + .mv_inw_p = hd64461_inw, + .mv_inl_p = hd64461_inl, + .mv_outb_p = hd64461_outb_p, + .mv_outw_p = hd64461_outw, + .mv_outl_p = hd64461_outl, + + .mv_insb = hd64461_insb, + .mv_insw = hd64461_insw, + .mv_insl = hd64461_insl, + .mv_outsb = hd64461_outsb, + .mv_outsw = hd64461_outsw, + .mv_outsl = hd64461_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, + + .mv_irq_demux = hd64461_irq_demux, + + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, + + .mv_hw_hp600 = 1, + .mv_hw_hp680 = 1, + .mv_hw_hd64461 = 1, }; ALIAS_MV(hp680) struct sh_machine_vector mv_hp690 __initmv = { - mv_name: "hp690", + .mv_name = "hp690", - mv_nr_irqs: HD64461_IRQBASE+HD64461_IRQ_NUM, + .mv_nr_irqs = HD64461_IRQBASE+HD64461_IRQ_NUM, - mv_inb: hd64461_inb, - mv_inw: hd64461_inw, - mv_inl: hd64461_inl, - mv_outb: hd64461_outb, - mv_outw: hd64461_outw, - mv_outl: hd64461_outl, - - mv_inb_p: hd64461_inb_p, - mv_inw_p: hd64461_inw, - mv_inl_p: hd64461_inl, - mv_outb_p: hd64461_outb_p, - mv_outw_p: hd64461_outw, - mv_outl_p: hd64461_outl, - - mv_insb: hd64461_insb, - mv_insw: hd64461_insw, - mv_insl: hd64461_insl, - mv_outsb: hd64461_outsb, - mv_outsw: hd64461_outsw, - mv_outsl: hd64461_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, - - mv_irq_demux: hd64461_irq_demux, - - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, - - mv_hw_hp600: 1, - mv_hw_hp690: 1, - mv_hw_hd64461: 1, + .mv_inb = hd64461_inb, + .mv_inw = hd64461_inw, + .mv_inl = hd64461_inl, + .mv_outb = hd64461_outb, + .mv_outw = hd64461_outw, + .mv_outl = hd64461_outl, + + .mv_inb_p = hd64461_inb_p, + .mv_inw_p = hd64461_inw, + .mv_inl_p = hd64461_inl, + .mv_outb_p = hd64461_outb_p, + .mv_outw_p = hd64461_outw, + .mv_outl_p = hd64461_outl, + + .mv_insb = hd64461_insb, + .mv_insw = hd64461_insw, + .mv_insl = hd64461_insl, + .mv_outsb = hd64461_outsb, + .mv_outsw = hd64461_outsw, + .mv_outsl = hd64461_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, + + .mv_irq_demux = hd64461_irq_demux, + + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, + + .mv_hw_hp600 = 1, + .mv_hw_hp690 = 1, + .mv_hw_hd64461 = 1, }; ALIAS_MV(hp690) diff -Nru a/arch/sh/kernel/mach_se.c b/arch/sh/kernel/mach_se.c --- a/arch/sh/kernel/mach_se.c Tue Oct 15 20:29:20 2002 +++ b/arch/sh/kernel/mach_se.c Tue Oct 15 20:29:20 2002 @@ -27,58 +27,58 @@ */ struct sh_machine_vector mv_se __initmv = { - mv_name: "SolutionEngine", + .mv_name = "SolutionEngine", #if defined(__SH4__) - mv_nr_irqs: 48, + .mv_nr_irqs = 48, #elif defined(CONFIG_CPU_SUBTYPE_SH7708) - mv_nr_irqs: 32, + .mv_nr_irqs = 32, #elif defined(CONFIG_CPU_SUBTYPE_SH7709) - mv_nr_irqs: 61, + .mv_nr_irqs = 61, #endif - mv_inb: se_inb, - mv_inw: se_inw, - mv_inl: se_inl, - mv_outb: se_outb, - mv_outw: se_outw, - mv_outl: se_outl, - - mv_inb_p: se_inb_p, - mv_inw_p: se_inw, - mv_inl_p: se_inl, - mv_outb_p: se_outb_p, - mv_outw_p: se_outw, - mv_outl_p: se_outl, - - mv_insb: se_insb, - mv_insw: se_insw, - mv_insl: se_insl, - mv_outsb: se_outsb, - mv_outsw: se_outsw, - mv_outsl: se_outsl, - - mv_readb: se_readb, - mv_readw: se_readw, - mv_readl: se_readl, - mv_writeb: se_writeb, - mv_writew: se_writew, - mv_writel: se_writel, + .mv_inb = se_inb, + .mv_inw = se_inw, + .mv_inl = se_inl, + .mv_outb = se_outb, + .mv_outw = se_outw, + .mv_outl = se_outl, + + .mv_inb_p = se_inb_p, + .mv_inw_p = se_inw, + .mv_inl_p = se_inl, + .mv_outb_p = se_outb_p, + .mv_outw_p = se_outw, + .mv_outl_p = se_outl, + + .mv_insb = se_insb, + .mv_insw = se_insw, + .mv_insl = se_insl, + .mv_outsb = se_outsb, + .mv_outsw = se_outsw, + .mv_outsl = se_outsl, + + .mv_readb = se_readb, + .mv_readw = se_readw, + .mv_readl = se_readl, + .mv_writeb = se_writeb, + .mv_writew = se_writew, + .mv_writel = se_writel, - mv_ioremap: generic_ioremap, - mv_iounmap: generic_iounmap, + .mv_ioremap = generic_ioremap, + .mv_iounmap = generic_iounmap, - mv_isa_port2addr: se_isa_port2addr, + .mv_isa_port2addr = se_isa_port2addr, - mv_init_arch: setup_se, - mv_init_irq: init_se_IRQ, + .mv_init_arch = setup_se, + .mv_init_irq = init_se_IRQ, #ifdef CONFIG_HEARTBEAT - mv_heartbeat: heartbeat_se, + .mv_heartbeat = heartbeat_se, #endif - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, - mv_hw_se: 1, + .mv_hw_se = 1, }; ALIAS_MV(se) diff -Nru a/arch/sh/kernel/mach_unknown.c b/arch/sh/kernel/mach_unknown.c --- a/arch/sh/kernel/mach_unknown.c Tue Oct 15 20:29:12 2002 +++ b/arch/sh/kernel/mach_unknown.c Tue Oct 15 20:29:12 2002 @@ -23,50 +23,50 @@ */ struct sh_machine_vector mv_unknown __initmv = { - mv_name: "Unknown", + .mv_name = "Unknown", #if defined(__SH4__) - mv_nr_irqs: 48, + .mv_nr_irqs = 48, #elif defined(CONFIG_CPU_SUBTYPE_SH7708) - mv_nr_irqs: 32, + .mv_nr_irqs = 32, #elif defined(CONFIG_CPU_SUBTYPE_SH7709) - mv_nr_irqs: 61, + .mv_nr_irqs = 61, #endif - mv_inb: unknown_inb, - mv_inw: unknown_inw, - mv_inl: unknown_inl, - mv_outb: unknown_outb, - mv_outw: unknown_outw, - mv_outl: unknown_outl, - - mv_inb_p: unknown_inb_p, - mv_inw_p: unknown_inw_p, - mv_inl_p: unknown_inl_p, - mv_outb_p: unknown_outb_p, - mv_outw_p: unknown_outw_p, - mv_outl_p: unknown_outl_p, - - mv_insb: unknown_insb, - mv_insw: unknown_insw, - mv_insl: unknown_insl, - mv_outsb: unknown_outsb, - mv_outsw: unknown_outsw, - mv_outsl: unknown_outsl, - - mv_readb: unknown_readb, - mv_readw: unknown_readw, - mv_readl: unknown_readl, - mv_writeb: unknown_writeb, - mv_writew: unknown_writew, - mv_writel: unknown_writel, + .mv_inb = unknown_inb, + .mv_inw = unknown_inw, + .mv_inl = unknown_inl, + .mv_outb = unknown_outb, + .mv_outw = unknown_outw, + .mv_outl = unknown_outl, + + .mv_inb_p = unknown_inb_p, + .mv_inw_p = unknown_inw_p, + .mv_inl_p = unknown_inl_p, + .mv_outb_p = unknown_outb_p, + .mv_outw_p = unknown_outw_p, + .mv_outl_p = unknown_outl_p, + + .mv_insb = unknown_insb, + .mv_insw = unknown_insw, + .mv_insl = unknown_insl, + .mv_outsb = unknown_outsb, + .mv_outsw = unknown_outsw, + .mv_outsl = unknown_outsl, + + .mv_readb = unknown_readb, + .mv_readw = unknown_readw, + .mv_readl = unknown_readl, + .mv_writeb = unknown_writeb, + .mv_writew = unknown_writew, + .mv_writel = unknown_writel, - mv_ioremap: unknown_ioremap, - mv_iounmap: unknown_iounmap, + .mv_ioremap = unknown_ioremap, + .mv_iounmap = unknown_iounmap, - mv_isa_port2addr: unknown_isa_port2addr, + .mv_isa_port2addr = unknown_isa_port2addr, - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, }; ALIAS_MV(unknown) diff -Nru a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c --- a/arch/sh/kernel/setup.c Tue Oct 15 20:29:17 2002 +++ b/arch/sh/kernel/setup.c Tue Oct 15 20:29:17 2002 @@ -171,12 +171,12 @@ } static struct console sh_console = { - name: "bios", - write: sh_console_write, - device: sh_console_device, - setup: sh_console_setup, - flags: CON_PRINTBUFFER, - index: -1, + .name = "bios", + .write = sh_console_write, + .device = sh_console_device, + .setup = sh_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; void sh_console_init(void) @@ -548,9 +548,9 @@ { } struct seq_operations cpuinfo_op = { - start: c_start, - next: c_next, - stop: c_stop, - show: show_cpuinfo, + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, }; #endif diff -Nru a/arch/sh/kernel/setup_cqreek.c b/arch/sh/kernel/setup_cqreek.c --- a/arch/sh/kernel/setup_cqreek.c Tue Oct 15 20:29:16 2002 +++ b/arch/sh/kernel/setup_cqreek.c Tue Oct 15 20:29:16 2002 @@ -200,53 +200,53 @@ */ struct sh_machine_vector mv_cqreek __initmv = { - mv_name: "CqREEK", + .mv_name = "CqREEK", #if defined(__SH4__) - mv_nr_irqs: 48, + .mv_nr_irqs = 48, #elif defined(CONFIG_CPU_SUBTYPE_SH7708) - mv_nr_irqs: 32, + .mv_nr_irqs = 32, #elif defined(CONFIG_CPU_SUBTYPE_SH7709) - mv_nr_irqs: 61, + .mv_nr_irqs = 61, #endif - mv_inb: generic_inb, - mv_inw: generic_inw, - mv_inl: generic_inl, - mv_outb: generic_outb, - mv_outw: generic_outw, - mv_outl: generic_outl, - - mv_inb_p: generic_inb_p, - mv_inw_p: generic_inw_p, - mv_inl_p: generic_inl_p, - mv_outb_p: generic_outb_p, - mv_outw_p: generic_outw_p, - mv_outl_p: generic_outl_p, - - mv_insb: generic_insb, - mv_insw: generic_insw, - mv_insl: generic_insl, - mv_outsb: generic_outsb, - mv_outsw: generic_outsw, - mv_outsl: generic_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, - - mv_init_arch: setup_cqreek, - mv_init_irq: init_cqreek_IRQ, + .mv_inb = generic_inb, + .mv_inw = generic_inw, + .mv_inl = generic_inl, + .mv_outb = generic_outb, + .mv_outw = generic_outw, + .mv_outl = generic_outl, + + .mv_inb_p = generic_inb_p, + .mv_inw_p = generic_inw_p, + .mv_inl_p = generic_inl_p, + .mv_outb_p = generic_outb_p, + .mv_outw_p = generic_outw_p, + .mv_outl_p = generic_outl_p, + + .mv_insb = generic_insb, + .mv_insw = generic_insw, + .mv_insl = generic_insl, + .mv_outsb = generic_outsb, + .mv_outsw = generic_outsw, + .mv_outsl = generic_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, + + .mv_init_arch = setup_cqreek, + .mv_init_irq = init_cqreek_IRQ, - mv_isa_port2addr: cqreek_port2addr, + .mv_isa_port2addr = cqreek_port2addr, - mv_ioremap: generic_ioremap, - mv_iounmap: generic_iounmap, + .mv_ioremap = generic_ioremap, + .mv_iounmap = generic_iounmap, - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, }; ALIAS_MV(cqreek) diff -Nru a/arch/sh/kernel/setup_dc.c b/arch/sh/kernel/setup_dc.c --- a/arch/sh/kernel/setup_dc.c Tue Oct 15 20:29:12 2002 +++ b/arch/sh/kernel/setup_dc.c Tue Oct 15 20:29:12 2002 @@ -123,13 +123,13 @@ } static struct hw_interrupt_type systemasic_int = { - typename: "System ASIC", - startup: startup_systemasic_irq, - shutdown: shutdown_systemasic_irq, - enable: enable_systemasic_irq, - disable: disable_systemasic_irq, - ack: ack_systemasic_irq, - end: end_systemasic_irq, + .typename = "System ASIC", + .startup = startup_systemasic_irq, + .shutdown = shutdown_systemasic_irq, + .enable = enable_systemasic_irq, + .disable = disable_systemasic_irq, + .ack = ack_systemasic_irq, + .end = end_systemasic_irq, }; /* diff -Nru a/arch/sh/kernel/setup_ec3104.c b/arch/sh/kernel/setup_ec3104.c --- a/arch/sh/kernel/setup_ec3104.c Tue Oct 15 20:29:21 2002 +++ b/arch/sh/kernel/setup_ec3104.c Tue Oct 15 20:29:21 2002 @@ -185,13 +185,13 @@ } static struct hw_interrupt_type ec3104_int = { - typename: "EC3104", - enable: enable_ec3104_irq, - disable: disable_ec3104_irq, - ack: mask_and_ack_ec3104_irq, - end: end_ec3104_irq, - startup: startup_ec3104_irq, - shutdown: shutdown_ec3104_irq, + .typename = "EC3104", + .enable = enable_ec3104_irq, + .disable = disable_ec3104_irq, + .ack = mask_and_ack_ec3104_irq, + .end = end_ec3104_irq, + .startup = startup_ec3104_irq, + .shutdown = shutdown_ec3104_irq, }; /* Yuck. the _demux API is ugly */ diff -Nru a/arch/sh/kernel/setup_hd64465.c b/arch/sh/kernel/setup_hd64465.c --- a/arch/sh/kernel/setup_hd64465.c Tue Oct 15 20:29:23 2002 +++ b/arch/sh/kernel/setup_hd64465.c Tue Oct 15 20:29:23 2002 @@ -89,13 +89,13 @@ static struct hw_interrupt_type hd64465_irq_type = { - typename: "HD64465-IRQ", - startup: startup_hd64465_irq, - shutdown: shutdown_hd64465_irq, - enable: enable_hd64465_irq, - disable: disable_hd64465_irq, - ack: mask_and_ack_hd64465, - end: end_hd64465_irq + .typename = "HD64465-IRQ", + .startup = startup_hd64465_irq, + .shutdown = shutdown_hd64465_irq, + .enable = enable_hd64465_irq, + .disable = disable_hd64465_irq, + .ack = mask_and_ack_hd64465, + .end = end_hd64465_irq }; diff -Nru a/arch/sh/kernel/setup_sh2000.c b/arch/sh/kernel/setup_sh2000.c --- a/arch/sh/kernel/setup_sh2000.c Tue Oct 15 20:29:15 2002 +++ b/arch/sh/kernel/setup_sh2000.c Tue Oct 15 20:29:15 2002 @@ -48,48 +48,48 @@ */ struct sh_machine_vector mv_sh2000 __initmv = { - mv_name: "sh2000", + .mv_name = "sh2000", - mv_nr_irqs: 80, + .mv_nr_irqs = 80, - mv_inb: generic_inb, - mv_inw: generic_inw, - mv_inl: generic_inl, - mv_outb: generic_outb, - mv_outw: generic_outw, - mv_outl: generic_outl, - - mv_inb_p: generic_inb_p, - mv_inw_p: generic_inw_p, - mv_inl_p: generic_inl_p, - mv_outb_p: generic_outb_p, - mv_outw_p: generic_outw_p, - mv_outl_p: generic_outl_p, - - mv_insb: generic_insb, - mv_insw: generic_insw, - mv_insl: generic_insl, - mv_outsb: generic_outsb, - mv_outsw: generic_outsw, - mv_outsl: generic_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, - - mv_init_arch: setup_sh2000, - - mv_isa_port2addr: sh2000_isa_port2addr, + .mv_inb = generic_inb, + .mv_inw = generic_inw, + .mv_inl = generic_inl, + .mv_outb = generic_outb, + .mv_outw = generic_outw, + .mv_outl = generic_outl, + + .mv_inb_p = generic_inb_p, + .mv_inw_p = generic_inw_p, + .mv_inl_p = generic_inl_p, + .mv_outb_p = generic_outb_p, + .mv_outw_p = generic_outw_p, + .mv_outl_p = generic_outl_p, + + .mv_insb = generic_insb, + .mv_insw = generic_insw, + .mv_insl = generic_insl, + .mv_outsb = generic_outsb, + .mv_outsw = generic_outsw, + .mv_outsl = generic_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, + + .mv_init_arch = setup_sh2000, + + .mv_isa_port2addr = sh2000_isa_port2addr, - mv_ioremap: generic_ioremap, - mv_iounmap: generic_iounmap, + .mv_ioremap = generic_ioremap, + .mv_iounmap = generic_iounmap, - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, - mv_hw_sh2000: 1, + .mv_hw_sh2000 = 1, }; ALIAS_MV(sh2000) diff -Nru a/arch/sh/stboards/mach.c b/arch/sh/stboards/mach.c --- a/arch/sh/stboards/mach.c Tue Oct 15 20:29:17 2002 +++ b/arch/sh/stboards/mach.c Tue Oct 15 20:29:17 2002 @@ -26,52 +26,52 @@ */ struct sh_machine_vector mv_harp __initmv = { - mv_name: "STB1 Harp", + .mv_name = "STB1 Harp", - mv_nr_irqs: 89 + HD64465_IRQ_NUM, + .mv_nr_irqs = 89 + HD64465_IRQ_NUM, - mv_inb: hd64465_inb, - mv_inw: hd64465_inw, - mv_inl: hd64465_inl, - mv_outb: hd64465_outb, - mv_outw: hd64465_outw, - mv_outl: hd64465_outl, - - mv_inb_p: hd64465_inb_p, - mv_inw_p: hd64465_inw, - mv_inl_p: hd64465_inl, - mv_outb_p: hd64465_outb_p, - mv_outw_p: hd64465_outw, - mv_outl_p: hd64465_outl, - - mv_insb: hd64465_insb, - mv_insw: hd64465_insw, - mv_insl: hd64465_insl, - mv_outsb: hd64465_outsb, - mv_outsw: hd64465_outsw, - mv_outsl: hd64465_outsl, - - mv_readb: generic_readb, - mv_readw: generic_readw, - mv_readl: generic_readl, - mv_writeb: generic_writeb, - mv_writew: generic_writew, - mv_writel: generic_writel, + .mv_inb = hd64465_inb, + .mv_inw = hd64465_inw, + .mv_inl = hd64465_inl, + .mv_outb = hd64465_outb, + .mv_outw = hd64465_outw, + .mv_outl = hd64465_outl, + + .mv_inb_p = hd64465_inb_p, + .mv_inw_p = hd64465_inw, + .mv_inl_p = hd64465_inl, + .mv_outb_p = hd64465_outb_p, + .mv_outw_p = hd64465_outw, + .mv_outl_p = hd64465_outl, + + .mv_insb = hd64465_insb, + .mv_insw = hd64465_insw, + .mv_insl = hd64465_insl, + .mv_outsb = hd64465_outsb, + .mv_outsw = hd64465_outsw, + .mv_outsl = hd64465_outsl, + + .mv_readb = generic_readb, + .mv_readw = generic_readw, + .mv_readl = generic_readl, + .mv_writeb = generic_writeb, + .mv_writew = generic_writew, + .mv_writel = generic_writel, - mv_ioremap: generic_ioremap, - mv_iounmap: generic_iounmap, + .mv_ioremap = generic_ioremap, + .mv_iounmap = generic_iounmap, - mv_isa_port2addr: hd64465_isa_port2addr, + .mv_isa_port2addr = hd64465_isa_port2addr, - mv_init_arch: setup_harp, + .mv_init_arch = setup_harp, #ifdef CONFIG_PCI - mv_init_irq: init_harp_irq, + .mv_init_irq = init_harp_irq, #endif #ifdef CONFIG_HEARTBEAT - mv_heartbeat: heartbeat_harp, + .mv_heartbeat = heartbeat_harp, #endif - mv_rtc_gettimeofday: sh_rtc_gettimeofday, - mv_rtc_settimeofday: sh_rtc_settimeofday, + .mv_rtc_gettimeofday = sh_rtc_gettimeofday, + .mv_rtc_settimeofday = sh_rtc_settimeofday, }; ALIAS_MV(harp) diff -Nru a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c --- a/arch/sparc/kernel/pcic.c Tue Oct 15 20:29:17 2002 +++ b/arch/sparc/kernel/pcic.c Tue Oct 15 20:29:17 2002 @@ -34,6 +34,8 @@ #include #include +extern rwlock_t xtime_lock; + #ifndef CONFIG_PCI asmlinkage int sys_pciconfig_read(unsigned long bus, @@ -737,8 +739,10 @@ static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs) { + write_lock(&xtime_lock); /* Dummy, to show that we remember */ pcic_clear_clock_irq(); do_timer(regs); + write_unlock(&xtime_lock); } #define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */ @@ -776,25 +780,17 @@ static __inline__ unsigned long do_gettimeoffset(void) { - struct tasklet_struct *t; - unsigned long offset = 0; - - /* + /* * We devide all to 100 * to have microsecond resolution and to avoid overflow */ - unsigned long count = + unsigned long count = readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); - - t = &bh_task_vec[TIMER_BH]; - if (test_bit(TASKLET_STATE_SCHED, &t->state)) - offset = 1000000; - return offset + count; + return count; } extern unsigned long wall_jiffies; -extern rwlock_t xtime_lock; static void pci_do_gettimeofday(struct timeval *tv) { diff -Nru a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c --- a/arch/sparc/kernel/time.c Tue Oct 15 20:29:17 2002 +++ b/arch/sparc/kernel/time.c Tue Oct 15 20:29:17 2002 @@ -129,6 +129,8 @@ sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]); #endif + /* Protect counter clear so that do_gettimeoffset works */ + write_lock(&xtime_lock); #ifdef CONFIG_SUN4 if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) || (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { @@ -140,8 +142,6 @@ #endif clear_clock_irq(); - write_lock(&xtime_lock); - do_timer(regs); /* Determine when to update the Mostek clock. */ @@ -459,17 +459,7 @@ extern __inline__ unsigned long do_gettimeoffset(void) { - struct tasklet_struct *t; - unsigned long offset = 0; - unsigned int count; - - count = (*master_l10_counter >> 10) & 0x1fffff; - - t = &bh_task_vec[TIMER_BH]; - if (test_bit(TASKLET_STATE_SCHED, &t->state)) - offset = 1000000; - - return offset + count; + return (*master_l10_counter >> 10) & 0x1fffff; } /* Ok, my cute asm atomicity trick doesn't work anymore. diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Tue Oct 15 20:29:16 2002 +++ b/arch/sparc64/defconfig Tue Oct 15 20:29:16 2002 @@ -32,6 +32,7 @@ # CONFIG_HUGETLB_PAGE is not set CONFIG_SMP=y # CONFIG_PREEMPT is not set +CONFIG_NR_CPUS=4 CONFIG_SPARC64=y CONFIG_HOTPLUG=y CONFIG_HAVE_DEC_LOCK=y @@ -59,7 +60,6 @@ CONFIG_BINFMT_MISC=m # CONFIG_SUNOS_EMUL is not set CONFIG_SOLARIS_EMUL=m -CONFIG_NR_CPUS=64 # # Parallel port support @@ -220,6 +220,8 @@ # CONFIG_BLK_DEV_GENERIC is not set # CONFIG_IDEPCI_SHARE_IRQ is not set CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDE_TCQ is not set +# CONFIG_BLK_DEV_IDE_TCQ_DEFAULT is not set # CONFIG_BLK_DEV_OFFBOARD is not set # CONFIG_BLK_DEV_IDEDMA_FORCED is not set CONFIG_IDEDMA_PCI_AUTO=y @@ -1025,15 +1027,20 @@ CONFIG_BLUEZ=m CONFIG_BLUEZ_L2CAP=m CONFIG_BLUEZ_SCO=m +CONFIG_BLUEZ_RFCOMM=m +CONFIG_BLUEZ_RFCOMM_TTY=y +CONFIG_BLUEZ_BNEP=m +CONFIG_BLUEZ_BNEP_MC_FILTER=y +CONFIG_BLUEZ_BNEP_PROTO_FILTER=y # # Bluetooth device drivers # CONFIG_BLUEZ_HCIUSB=m -CONFIG_BLUEZ_USB_FW_LOAD=y CONFIG_BLUEZ_USB_ZERO_PACKET=y CONFIG_BLUEZ_HCIUART=m CONFIG_BLUEZ_HCIUART_H4=y +CONFIG_BLUEZ_HCIUART_BCSP=y # CONFIG_BLUEZ_HCIDTL1 is not set # CONFIG_BLUEZ_HCIBT3C is not set # CONFIG_BLUEZ_HCIBLUECARD is not set diff -Nru a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c --- a/arch/sparc64/kernel/ebus.c Tue Oct 15 20:29:15 2002 +++ b/arch/sparc64/kernel/ebus.c Tue Oct 15 20:29:15 2002 @@ -247,7 +247,7 @@ mem = kmalloc(size, GFP_ATOMIC); if (!mem) - panic(__FUNCTION__ ": out of memory"); + panic("ebus_alloc: out of memory"); memset((char *)mem, 0, size); return mem; } diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c --- a/arch/sparc64/kernel/pci.c Tue Oct 15 20:29:10 2002 +++ b/arch/sparc64/kernel/pci.c Tue Oct 15 20:29:10 2002 @@ -72,10 +72,134 @@ */ int pci_device_reorder = 0; -spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED; volatile int pci_poke_in_progress; volatile int pci_poke_cpu = -1; volatile int pci_poke_faulted; + +static spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED; + +void pci_config_read8(u8 *addr, u8 *ret) +{ + unsigned long flags; + u8 byte; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduba [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (byte) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + pci_poke_cpu = -1; + if (!pci_poke_faulted) + *ret = byte; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +void pci_config_read16(u16 *addr, u16 *ret) +{ + unsigned long flags; + u16 word; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduha [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (word) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + pci_poke_cpu = -1; + if (!pci_poke_faulted) + *ret = word; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +void pci_config_read32(u32 *addr, u32 *ret) +{ + unsigned long flags; + u32 dword; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduwa [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (dword) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + pci_poke_cpu = -1; + if (!pci_poke_faulted) + *ret = dword; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +void pci_config_write8(u8 *addr, u8 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stba %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + pci_poke_cpu = -1; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +void pci_config_write16(u16 *addr, u16 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stha %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + pci_poke_cpu = -1; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +void pci_config_write32(u32 *addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_cpu = smp_processor_id(); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stwa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + pci_poke_cpu = -1; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} /* Probe for all PCI controllers in the system. */ extern void sabre_init(int, char *); diff -Nru a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h --- a/arch/sparc64/kernel/pci_impl.h Tue Oct 15 20:29:10 2002 +++ b/arch/sparc64/kernel/pci_impl.h Tue Oct 15 20:29:10 2002 @@ -42,132 +42,11 @@ extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); /* Configuration space access. */ -extern spinlock_t pci_poke_lock; -extern volatile int pci_poke_in_progress; -extern volatile int pci_poke_cpu; -extern volatile int pci_poke_faulted; - -static __inline__ void pci_config_read8(u8 *addr, u8 *ret) -{ - unsigned long flags; - u8 byte; - - spin_lock_irqsave(&pci_poke_lock, flags); - pci_poke_cpu = smp_processor_id(); - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "lduba [%1] %2, %0\n\t" - "membar #Sync" - : "=r" (byte) - : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) - : "memory"); - pci_poke_in_progress = 0; - pci_poke_cpu = -1; - if (!pci_poke_faulted) - *ret = byte; - spin_unlock_irqrestore(&pci_poke_lock, flags); -} - -static __inline__ void pci_config_read16(u16 *addr, u16 *ret) -{ - unsigned long flags; - u16 word; - - spin_lock_irqsave(&pci_poke_lock, flags); - pci_poke_cpu = smp_processor_id(); - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "lduha [%1] %2, %0\n\t" - "membar #Sync" - : "=r" (word) - : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) - : "memory"); - pci_poke_in_progress = 0; - pci_poke_cpu = -1; - if (!pci_poke_faulted) - *ret = word; - spin_unlock_irqrestore(&pci_poke_lock, flags); -} - -static __inline__ void pci_config_read32(u32 *addr, u32 *ret) -{ - unsigned long flags; - u32 dword; - - spin_lock_irqsave(&pci_poke_lock, flags); - pci_poke_cpu = smp_processor_id(); - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "lduwa [%1] %2, %0\n\t" - "membar #Sync" - : "=r" (dword) - : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) - : "memory"); - pci_poke_in_progress = 0; - pci_poke_cpu = -1; - if (!pci_poke_faulted) - *ret = dword; - spin_unlock_irqrestore(&pci_poke_lock, flags); -} - -static __inline__ void pci_config_write8(u8 *addr, u8 val) -{ - unsigned long flags; - - spin_lock_irqsave(&pci_poke_lock, flags); - pci_poke_cpu = smp_processor_id(); - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "stba %0, [%1] %2\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) - : "memory"); - pci_poke_in_progress = 0; - pci_poke_cpu = -1; - spin_unlock_irqrestore(&pci_poke_lock, flags); -} - -static __inline__ void pci_config_write16(u16 *addr, u16 val) -{ - unsigned long flags; - - spin_lock_irqsave(&pci_poke_lock, flags); - pci_poke_cpu = smp_processor_id(); - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "stha %0, [%1] %2\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) - : "memory"); - pci_poke_in_progress = 0; - pci_poke_cpu = -1; - spin_unlock_irqrestore(&pci_poke_lock, flags); -} - -static __inline__ void pci_config_write32(u32 *addr, u32 val) -{ - unsigned long flags; - - spin_lock_irqsave(&pci_poke_lock, flags); - pci_poke_cpu = smp_processor_id(); - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "stwa %0, [%1] %2\n\t" - "membar #Sync" - : /* no outputs */ - : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) - : "memory"); - pci_poke_in_progress = 0; - pci_poke_cpu = -1; - spin_unlock_irqrestore(&pci_poke_lock, flags); -} +extern void pci_config_read8(u8 *addr, u8 *ret); +extern void pci_config_read16(u16 *addr, u16 *ret); +extern void pci_config_read32(u32 *addr, u32 *ret); +extern void pci_config_write8(u8 *addr, u8 val); +extern void pci_config_write16(u16 *addr, u16 val); +extern void pci_config_write32(u32 *addr, u32 val); #endif /* !(PCI_IMPL_H) */ diff -Nru a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c --- a/arch/sparc64/kernel/semaphore.c Tue Oct 15 20:29:14 2002 +++ b/arch/sparc64/kernel/semaphore.c Tue Oct 15 20:29:14 2002 @@ -40,13 +40,57 @@ return old_count; } -void __up(struct semaphore *sem) +static void __up(struct semaphore *sem) { __sem_update_count(sem, 1); wake_up(&sem->wait); } -void __down(struct semaphore * sem) +void up(struct semaphore *sem) +{ + /* This atomically does: + * old_val = sem->count; + * new_val = sem->count + 1; + * sem->count = new_val; + * if (old_val < 0) + * __up(sem); + * + * The (old_val < 0) test is equivalent to + * the more straightforward (new_val <= 0), + * but it is easier to test the former because + * of how the CAS instruction works. + */ + + __asm__ __volatile__("\n" +" ! up sem(%0)\n" +" membar #StoreLoad | #LoadLoad\n" +"1: lduw [%0], %%g5\n" +" add %%g5, 1, %%g7\n" +" cas [%0], %%g5, %%g7\n" +" cmp %%g5, %%g7\n" +" bne,pn %%icc, 1b\n" +" addcc %%g7, 1, %%g0\n" +" ble,pn %%icc, 3f\n" +" membar #StoreLoad | #StoreStore\n" +"2:\n" +" .subsection 2\n" +"3: mov %0, %%g5\n" +" save %%sp, -160, %%sp\n" +" mov %%g1, %%l1\n" +" mov %%g2, %%l2\n" +" mov %%g3, %%l3\n" +" call %1\n" +" mov %%g5, %%o0\n" +" mov %%l1, %%g1\n" +" mov %%l2, %%g2\n" +" ba,pt %%xcc, 2b\n" +" restore %%l3, %%g0, %%g3\n" +" .previous\n" + : : "r" (sem), "i" (__up) + : "g5", "g7", "memory", "cc"); +} + +static void __down(struct semaphore * sem) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); @@ -64,7 +108,90 @@ wake_up(&sem->wait); } -int __down_interruptible(struct semaphore * sem) +void down(struct semaphore *sem) +{ + /* This atomically does: + * old_val = sem->count; + * new_val = sem->count - 1; + * sem->count = new_val; + * if (old_val < 1) + * __down(sem); + * + * The (old_val < 1) test is equivalent to + * the more straightforward (new_val < 0), + * but it is easier to test the former because + * of how the CAS instruction works. + */ + + __asm__ __volatile__("\n" +" ! down sem(%0)\n" +"1: lduw [%0], %%g5\n" +" sub %%g5, 1, %%g7\n" +" cas [%0], %%g5, %%g7\n" +" cmp %%g5, %%g7\n" +" bne,pn %%icc, 1b\n" +" cmp %%g7, 1\n" +" bl,pn %%icc, 3f\n" +" membar #StoreLoad | #StoreStore\n" +"2:\n" +" .subsection 2\n" +"3: mov %0, %%g5\n" +" save %%sp, -160, %%sp\n" +" mov %%g1, %%l1\n" +" mov %%g2, %%l2\n" +" mov %%g3, %%l3\n" +" call %1\n" +" mov %%g5, %%o0\n" +" mov %%l1, %%g1\n" +" mov %%l2, %%g2\n" +" ba,pt %%xcc, 2b\n" +" restore %%l3, %%g0, %%g3\n" +" .previous\n" + : : "r" (sem), "i" (__down) + : "g5", "g7", "memory", "cc"); +} + +int down_trylock(struct semaphore *sem) +{ + int ret; + + /* This atomically does: + * old_val = sem->count; + * new_val = sem->count - 1; + * if (old_val < 1) { + * ret = 1; + * } else { + * sem->count = new_val; + * ret = 0; + * } + * + * The (old_val < 1) test is equivalent to + * the more straightforward (new_val < 0), + * but it is easier to test the former because + * of how the CAS instruction works. + */ + + __asm__ __volatile__("\n" +" ! down_trylock sem(%1) ret(%0)\n" +"1: lduw [%1], %%g5\n" +" sub %%g5, 1, %%g7\n" +" cmp %%g5, 1\n" +" bl,pn %%icc, 2f\n" +" mov 1, %0\n" +" cas [%1], %%g5, %%g7\n" +" cmp %%g5, %%g7\n" +" bne,pn %%icc, 1b\n" +" mov 0, %0\n" +" membar #StoreLoad | #StoreStore\n" +"2:\n" + : "=&r" (ret) + : "r" (sem) + : "g5", "g7", "memory", "cc"); + + return ret; +} + +static int __down_interruptible(struct semaphore * sem) { int retval = 0; struct task_struct *tsk = current; @@ -86,4 +213,52 @@ remove_wait_queue(&sem->wait, &wait); wake_up(&sem->wait); return retval; +} + +int down_interruptible(struct semaphore *sem) +{ + int ret = 0; + + /* This atomically does: + * old_val = sem->count; + * new_val = sem->count - 1; + * sem->count = new_val; + * if (old_val < 1) + * ret = __down_interruptible(sem); + * + * The (old_val < 1) test is equivalent to + * the more straightforward (new_val < 0), + * but it is easier to test the former because + * of how the CAS instruction works. + */ + + __asm__ __volatile__("\n" +" ! down_interruptible sem(%2) ret(%0)\n" +"1: lduw [%2], %%g5\n" +" sub %%g5, 1, %%g7\n" +" cas [%2], %%g5, %%g7\n" +" cmp %%g5, %%g7\n" +" bne,pn %%icc, 1b\n" +" cmp %%g7, 1\n" +" bl,pn %%icc, 3f\n" +" membar #StoreLoad | #StoreStore\n" +"2:\n" +" .subsection 2\n" +"3: mov %2, %%g5\n" +" save %%sp, -160, %%sp\n" +" mov %%g1, %%l1\n" +" mov %%g2, %%l2\n" +" mov %%g3, %%l3\n" +" call %3\n" +" mov %%g5, %%o0\n" +" mov %%l1, %%g1\n" +" mov %%l2, %%g2\n" +" mov %%l3, %%g3\n" +" ba,pt %%xcc, 2b\n" +" restore %%o0, %%g0, %0\n" +" .previous\n" + : "=r" (ret) + : "0" (ret), "r" (sem), "i" (__down_interruptible) + : "g5", "g7", "memory", "cc"); + return ret; } diff -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c --- a/arch/sparc64/kernel/signal32.c Tue Oct 15 20:29:11 2002 +++ b/arch/sparc64/kernel/signal32.c Tue Oct 15 20:29:11 2002 @@ -230,7 +230,7 @@ } } -static inline int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) +static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = current_thread_info()->fpregs; unsigned long fprs; @@ -477,7 +477,7 @@ return 0; } -static inline void *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) +static void *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) { unsigned long sp; @@ -645,7 +645,7 @@ } -static inline int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) +static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = current_thread_info()->fpregs; unsigned long fprs; @@ -665,8 +665,8 @@ return err; } -static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, - int signo, sigset_t *oldset) +static void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, + int signo, sigset_t *oldset) { struct new_signal_frame32 *sf; int sigframe_size; @@ -790,7 +790,7 @@ } /* Setup a Solaris stack frame */ -static inline void +static void setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, struct pt_regs *regs, int signr, sigset_t *oldset) { @@ -1089,9 +1089,9 @@ do_exit(SIGSEGV); } -static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, - unsigned long signr, sigset_t *oldset, - siginfo_t *info) +static void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs, + unsigned long signr, sigset_t *oldset, + siginfo_t *info) { struct rt_signal_frame32 *sf; int sigframe_size; diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c Tue Oct 15 20:29:20 2002 +++ b/arch/sparc64/kernel/sparc64_ksyms.c Tue Oct 15 20:29:20 2002 @@ -161,9 +161,10 @@ #endif /* semaphores */ -EXPORT_SYMBOL(__down); -EXPORT_SYMBOL(__down_interruptible); -EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(down); +EXPORT_SYMBOL(down_trylock); +EXPORT_SYMBOL(down_interruptible); +EXPORT_SYMBOL(up); /* Atomic counter implementation. */ EXPORT_SYMBOL(__atomic_add); @@ -332,6 +333,7 @@ EXPORT_SYMBOL(__memmove); EXPORT_SYMBOL(csum_partial_copy_sparc64); +EXPORT_SYMBOL(ip_fast_csum); /* Moving data to/from userspace. */ EXPORT_SYMBOL(__copy_to_user); diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c --- a/arch/sparc64/kernel/sys_sparc32.c Tue Oct 15 20:29:17 2002 +++ b/arch/sparc64/kernel/sys_sparc32.c Tue Oct 15 20:29:17 2002 @@ -273,7 +273,7 @@ struct timeval32 it_value; }; -static inline long get_tv32(struct timeval *o, struct timeval32 *i) +static long get_tv32(struct timeval *o, struct timeval32 *i) { return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) || (__get_user(o->tv_sec, &i->tv_sec) | @@ -296,7 +296,7 @@ __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); } -static inline long put_it32(struct itimerval32 *o, struct itimerval *i) +static long put_it32(struct itimerval32 *o, struct itimerval *i) { return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) || (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | @@ -890,7 +890,7 @@ return sys32_fcntl(fd, cmd, arg); } -static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) +static int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf) { int err; @@ -1272,8 +1272,7 @@ * 64-bit unsigned longs. */ -static inline int -get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset) +static int get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset) { if (ufdset) { unsigned long odd; @@ -1303,8 +1302,7 @@ return 0; } -static inline void -set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset) +static void set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset) { unsigned long odd; @@ -2217,8 +2215,8 @@ return tot_len; } -static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg, - struct msghdr32 *umsg) +static int msghdr_from_user32_to_kern(struct msghdr *kmsg, + struct msghdr32 *umsg) { u32 tmp1, tmp2, tmp3; int err; @@ -2599,20 +2597,33 @@ sock = sockfd_lookup(fd, &err); if (sock != NULL) { - struct scm_cookie scm; + struct sock_iocb *si; + struct kiocb iocb; if (sock->file->f_flags & O_NONBLOCK) user_flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - err = sock->ops->recvmsg(sock, &kern_msg, total_len, - user_flags, &scm); + + init_sync_kiocb(&iocb, NULL); + si = kiocb_to_siocb(&iocb); + si->sock = sock; + si->scm = &si->async_scm; + si->msg = &kern_msg; + si->size = total_len; + si->flags = user_flags; + memset(si->scm, 0, sizeof(*si->scm)); + + err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len, + user_flags, si->scm); + if (-EIOCBQUEUED == err) + err = wait_on_sync_kiocb(&iocb); + if(err >= 0) { len = err; if(!kern_msg.msg_control) { - if(sock->passcred || scm.fp) + if(sock->passcred || si->scm->fp) kern_msg.msg_flags |= MSG_CTRUNC; - if(scm.fp) - __scm_destroy(&scm); + if(si->scm->fp) + __scm_destroy(si->scm); } else { /* If recvmsg processing itself placed some * control messages into user space, it's is @@ -2626,9 +2637,10 @@ if(sock->passcred) put_cmsg32(&kern_msg, SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), &scm.creds); - if(scm.fp != NULL) - scm_detach_fds32(&kern_msg, &scm); + sizeof(si->scm->creds), + &si->scm->creds); + if(si->scm->fp != NULL) + scm_detach_fds32(&kern_msg, si->scm); } } sockfd_put(sock); diff -Nru a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c --- a/arch/sparc64/kernel/unaligned.c Tue Oct 15 20:29:15 2002 +++ b/arch/sparc64/kernel/unaligned.c Tue Oct 15 20:29:15 2002 @@ -149,8 +149,8 @@ } } -static inline unsigned long compute_effective_address(struct pt_regs *regs, - unsigned int insn, unsigned int rd) +static unsigned long compute_effective_address(struct pt_regs *regs, + unsigned int insn, unsigned int rd) { unsigned int rs1 = (insn >> 14) & 0x1f; unsigned int rs2 = insn & 0x1f; diff -Nru a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile --- a/arch/sparc64/lib/Makefile Tue Oct 15 20:29:12 2002 +++ b/arch/sparc64/lib/Makefile Tue Oct 15 20:29:12 2002 @@ -10,6 +10,6 @@ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o mcount.o + U3copy_in_user.o mcount.o ipcsum.o include $(TOPDIR)/Rules.make diff -Nru a/arch/sparc64/lib/ipcsum.S b/arch/sparc64/lib/ipcsum.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/sparc64/lib/ipcsum.S Tue Oct 15 20:29:25 2002 @@ -0,0 +1,32 @@ + .text + .align 32 + .globl ip_fast_csum +ip_fast_csum: /* %o0 = iph, %o1 = ihl */ + sub %o1, 4, %g7 + lduw [%o0 + 0x00], %o2 + lduw [%o0 + 0x04], %g2 + lduw [%o0 + 0x08], %g3 + addcc %g2, %o2, %o2 + lduw [%o0 + 0x0c], %g2 + addccc %g3, %o2, %o2 + lduw [%o0 + 0x10], %g3 + + addccc %g2, %o2, %o2 + addc %o2, %g0, %o2 +1: addcc %g3, %o2, %o2 + add %o0, 4, %o0 + addccc %o2, %g0, %o2 + subcc %g7, 1, %g7 + be,a,pt %icc, 2f + sll %o2, 16, %g2 + + lduw [%o0 + 0x10], %g3 + ba,pt %xcc, 1b + nop +2: addcc %o2, %g2, %g2 + srl %g2, 16, %o2 + addc %o2, %g0, %o2 + xnor %g0, %o2, %o2 + set 0xffff, %o1 + retl + and %o2, %o1, %o0 diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c --- a/arch/sparc64/mm/fault.c Tue Oct 15 20:29:22 2002 +++ b/arch/sparc64/mm/fault.c Tue Oct 15 20:29:22 2002 @@ -222,7 +222,7 @@ extern int handle_ldf_stq(u32, struct pt_regs *); extern int handle_ld_nf(u32, struct pt_regs *); -static inline unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) +static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) { if (!insn) { if (!regs->tpc || (regs->tpc & 0x3)) diff -Nru a/arch/um/Makefile b/arch/um/Makefile --- a/arch/um/Makefile Tue Oct 15 20:29:12 2002 +++ b/arch/um/Makefile Tue Oct 15 20:29:12 2002 @@ -43,22 +43,13 @@ # in CFLAGS. Otherwise, it would cause ld to complain about the two different # errnos. -CFLAGS += $(DEBUG) $(PROFILE) $(ARCH_CFLAGS) -D__arch_um__ \ - -DSUBARCH=\"$(SUBARCH)\" -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) \ - -Derrno=kernel_errno +CFLAGS += $(DEBUG) $(PROFILE) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ + -D_LARGEFILE64_SOURCE -I$(ARCH_INCLUDE) -Derrno=kernel_errno LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) -$(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S - $(call if_changed_dep,as_s_S) - -AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \ - -DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum - -LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o - SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ include/asm-um/sigcontext.h include/asm-um/processor.h \ include/asm-um/ptrace.h include/asm-um/arch-signal.h @@ -71,11 +62,25 @@ $(ARCH_DIR)/vmlinux.lds.S : touch $@ -linux: scripts $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) \ - arch/um/uml.lds.s $(ARCH_DIR)/main.o vmlinux +prepare: $(ARCH_SYMLINKS) $(GEN_HEADERS) + + +LDFLAGS_vmlinux = -r $(ARCH_DIR)/main.o + +vmlinux: $(ARCH_DIR)/main.o + + +$(ARCH_DIR)/uml.lds.s : $(ARCH_DIR)/uml.lds.S + $(call if_changed_dep,as_s_S) + +AFLAGS_uml.lds.o = -U$(SUBARCH) -DSTART=$$(($(TOP_ADDR) - $(SIZE))) \ + -DELF_ARCH=$(ELF_ARCH) -DELF_FORMAT=\"$(ELF_FORMAT)\" -P -C -Uum + +linux: arch/um/uml.lds.s vmlinux $(CC) -Wl,-T,arch/um/uml.lds.s -o $@ $(LINK_PROFILE) \ $(LINK_WRAPS) -static vmlinux -L/usr/lib -lutil + USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) -I$(ARCH_INCLUDE) @@ -125,8 +130,9 @@ $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task $< > $@ -$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \ - $(ARCH_DIR)/util/mk_task_kern.c - $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util all +$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util FORCE ; + +$(ARCH_DIR)/util: FORCE + @$(call descend,$@,) export SUBARCH USER_CFLAGS OS diff -Nru a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 --- a/arch/um/Makefile-i386 Tue Oct 15 20:29:14 2002 +++ b/arch/um/Makefile-i386 Tue Oct 15 20:29:14 2002 @@ -4,31 +4,28 @@ TOP_ADDR = 0xc0000000 endif -ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH) +CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) ELF_ARCH = $(SUBARCH) ELF_FORMAT = elf32-$(SUBARCH) +SYS_DIR := $(ARCH_DIR)/include/sysdep-i386 +SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util -SYS_HEADERS = $(ARCH_DIR)/include/sysdep-i386/sc.h \ - $(ARCH_DIR)/include/sysdep-i386/thread.h +SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h -$(ARCH_DIR)/include/sysdep-i386/sc.h : $(ARCH_DIR)/sys-i386/util/mk_sc \ - include/asm - $(ARCH_DIR)/sys-i386/util/mk_sc > $@ - -$(ARCH_DIR)/include/sysdep-i386/thread.h : $(ARCH_DIR)/sys-i386/util/mk_thread\ - include/asm - $(ARCH_DIR)/sys-i386/util/mk_thread > $@ - -$(ARCH_DIR)/sys-i386/util/mk_sc : $(ARCH_DIR)/sys-i386/util/mk_sc.c \ - include/asm - $(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_sc - -$(ARCH_DIR)/sys-i386/util/mk_thread : \ - $(ARCH_DIR)/sys-i386/util/mk_thread_user.c \ - $(ARCH_DIR)/sys-i386/util/mk_thread_kern.c - $(MAKE) -C $(ARCH_DIR)/sys-i386/util mk_thread +prepare: $(SYS_HEADERS) + +$(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc + $< > $@ + +$(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread + $< > $@ + +$(SYS_UTIL_DIR)/mk_sc $(SYS_UTIL_DIR)/mk_thread: $(SYS_UTIL_DIR) FORCE ; + +$(SYS_UTIL_DIR): include/asm FORCE + @$(call descend,$@,) sysclean : rm -f $(SYS_HEADERS) - make -C $(ARCH_DIR)/sys-i386/util clean + @$(call descend,$(SYS_DIR),clean) diff -Nru a/arch/um/config.in b/arch/um/config.in --- a/arch/um/config.in Tue Oct 15 20:29:23 2002 +++ b/arch/um/config.in Tue Oct 15 20:29:23 2002 @@ -28,8 +28,13 @@ bool 'Management console' CONFIG_MCONSOLE dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE bool '2G/2G host address space split' CONFIG_HOST_2G_2G + bool 'Symmetric multi-processing support' CONFIG_UML_SMP define_bool CONFIG_SMP $CONFIG_UML_SMP +if [ "$CONFIG_SMP" = "y" ]; then + int 'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32 +fi + int 'Nesting level' CONFIG_NEST_LEVEL 0 int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1 bool 'Highmem support' CONFIG_HIGHMEM diff -Nru a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c --- a/arch/um/drivers/chan_user.c Tue Oct 15 20:29:11 2002 +++ b/arch/um/drivers/chan_user.c Tue Oct 15 20:29:11 2002 @@ -155,6 +155,8 @@ errno); } +/* Called only by the tracing thread during initialization */ + void setup_tracer_winch(void) { int err; diff -Nru a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c --- a/arch/um/drivers/harddog_kern.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/drivers/harddog_kern.c Tue Oct 15 20:29:17 2002 @@ -51,8 +51,8 @@ MODULE_LICENSE("GPL"); +/* Locked by the BKL in harddog_open and harddog_release */ static int timer_alive; - static int harddog_in_fd = -1; static int harddog_out_fd = -1; @@ -67,6 +67,7 @@ int err; char *sock = NULL; + lock_kernel(); if(timer_alive) return -EBUSY; #ifdef CONFIG_HARDDOG_NOWAYOUT @@ -80,6 +81,7 @@ if(err) return(err); timer_alive = 1; + unlock_kernel(); return 0; } diff -Nru a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c --- a/arch/um/drivers/hostaudio_kern.c Tue Oct 15 20:29:16 2002 +++ b/arch/um/drivers/hostaudio_kern.c Tue Oct 15 20:29:16 2002 @@ -15,6 +15,7 @@ #include "init.h" #include "hostaudio.h" +/* Only changed from linux_main at boot time */ char *dsp = HOSTAUDIO_DEV_DSP; char *mixer = HOSTAUDIO_DEV_MIXER; diff -Nru a/arch/um/drivers/line.c b/arch/um/drivers/line.c --- a/arch/um/drivers/line.c Tue Oct 15 20:29:21 2002 +++ b/arch/um/drivers/line.c Tue Oct 15 20:29:21 2002 @@ -99,19 +99,27 @@ i = minor(tty->device) - tty->driver.minor_start; line = &lines[i]; + down(&line->sem); if(line->head != line->tail){ local_irq_save(flags); buffer_data(line, buf, len); err = flush_buffer(line); local_irq_restore(flags); - if(err <= 0) return(len); + if(err <= 0) + goto out; } else { n = write_chan(&line->chan_list, buf, len, line->driver->write_irq); - if(n < 0) return(n); - if(n < len) buffer_data(line, buf + n, len - n); + if(n < 0){ + len = n; + goto out; + } + if(n < len) + buffer_data(line, buf + n, len - n); } + out: + up(&line->sem); return(len); } @@ -249,6 +257,7 @@ else n = minor(tty->device) - tty->driver.minor_start; line = &lines[n]; + down(&line->sem); line->count--; /* I don't like this, but I can't think of anything better. What's @@ -261,6 +270,7 @@ line->tty = NULL; if(line->count == 0) line_disable(line, -1); + up(&line->sem); } void close_lines(struct line *lines, int nlines) @@ -343,8 +353,6 @@ driver->write_room = line_write_room; driver->init_termios = tty_std_termios; - driver->refcount = &set->refcount; - if (tty_register_driver(driver)) panic("line_register_devfs : Couldn't register driver\n"); @@ -408,16 +416,18 @@ reactivate_fd(winch->fd, WINCH_IRQ); } +DECLARE_MUTEX(winch_handler_sem); LIST_HEAD(winch_handlers); void register_winch_irq(int fd, int tty_fd, int pid, void *line) { struct winch *winch; + down(&winch_handler_sem); winch = kmalloc(sizeof(*winch), GFP_KERNEL); if(winch == NULL){ printk("register_winch_irq - kmalloc failed\n"); - return; + goto out; } *winch = ((struct winch) { list : LIST_HEAD_INIT(winch->list), fd : fd, @@ -429,6 +439,8 @@ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "winch", winch) < 0) printk("register_winch_irq - failed to register IRQ\n"); + out: + up(&winch_handler_sem); } static void winch_cleanup(void) @@ -439,7 +451,6 @@ list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); close(winch->fd); - free_irq_by_fd(winch->fd); if(winch->pid != -1) os_kill_process(winch->pid); } } diff -Nru a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c --- a/arch/um/drivers/mconsole_kern.c Tue Oct 15 20:29:11 2002 +++ b/arch/um/drivers/mconsole_kern.c Tue Oct 15 20:29:11 2002 @@ -40,6 +40,11 @@ priority: 0, }; +/* Safe without explicit locking for now. Tasklets provide their own + * locking, and the interrupt handler is safe because it can't interrupt + * itself and it can only happen on CPU 0. + */ + LIST_HEAD(mc_requests); void mc_work_proc(void *unused) @@ -49,12 +54,12 @@ int done; do { - save_flags(flags); + local_save_flags(flags); req = list_entry(mc_requests.next, struct mconsole_entry, list); list_del(&req->list); done = list_empty(&mc_requests); - restore_flags(flags); + local_irq_restore(flags); req->request.cmd->handler(&req->request); kfree(req); } while(!done); @@ -152,6 +157,8 @@ mconsole_reply(req, "", 0, 0); } +/* This list is populated by __initcall routines. */ + LIST_HEAD(mconsole_devices); void mconsole_register_dev(struct mc_device *new) @@ -224,7 +231,10 @@ } #endif -static char *notify_socket = NULL; +/* Changed by mconsole_setup, which is __setup, and called before SMP is + * active. + */ +static char *notify_socket = NULL; int mconsole_init(void) { @@ -299,6 +309,18 @@ ent->read_proc = NULL; ent->write_proc = write_proc_mconsole; return(0); +} + +static spinlock_t notify_spinlock = SPIN_LOCK_UNLOCKED; + +void lock_notify(void) +{ + spin_lock(¬ify_spinlock); +} + +void unlock_notify(void) +{ + spin_unlock(¬ify_spinlock); } __initcall(create_proc_mconsole); diff -Nru a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c --- a/arch/um/drivers/mconsole_user.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/drivers/mconsole_user.c Tue Oct 15 20:29:12 2002 @@ -30,6 +30,7 @@ { "go", mconsole_go, 1 }, }; +/* Initialized in mconsole_init, which is an initcall */ char mconsole_socket_name[256]; int mconsole_reply_v0(struct mc_request *req, char *reply) @@ -162,16 +163,21 @@ { struct sockaddr_un target; struct mconsole_notify packet; - int n, err; + int n, err = 0; + lock_notify(); if(notify_sock < 0){ notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0); if(notify_sock < 0){ printk("mconsole_notify - socket failed, errno = %d\n", errno); - return(-errno); + err = -errno; } } + unlock_notify(); + + if(err) + return(err); target.sun_family = AF_UNIX; strcpy(target.sun_path, sock_name); diff -Nru a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c --- a/arch/um/drivers/mmapper_kern.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/drivers/mmapper_kern.c Tue Oct 15 20:29:12 2002 @@ -15,13 +15,14 @@ #include #include #include +#include #include #include -#include #include #include "mem_user.h" #include "user_util.h" +/* These are set in mmapper_init, which is called at boot time */ static unsigned long mmapper_size; static unsigned long p_buf = 0; static char *v_buf = NULL; diff -Nru a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c --- a/arch/um/drivers/net_kern.c Tue Oct 15 20:29:16 2002 +++ b/arch/um/drivers/net_kern.c Tue Oct 15 20:29:16 2002 @@ -27,6 +27,7 @@ #include "init.h" #include "irq_user.h" +static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED; LIST_HEAD(opened); static int uml_net_rx(struct net_device *dev) @@ -118,7 +119,9 @@ lp->tl.data = (unsigned long) &lp->user; netif_start_queue(dev); + spin_lock(&opened_lock); list_add(&lp->list, &opened); + spin_unlock(&opened_lock); MOD_INC_USE_COUNT; out: spin_unlock(&lp->lock); @@ -135,8 +138,10 @@ free_irq(dev->irq, dev); if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); lp->fd = -1; + spin_lock(&opened_lock); list_del(&lp->list); - + spin_unlock(&opened_lock); + MOD_DEC_USE_COUNT; spin_unlock(&lp->lock); return 0; @@ -245,6 +250,7 @@ #endif } +static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; static struct list_head devices = LIST_HEAD_INIT(devices); static int eth_configure(int n, void *init, char *mac, @@ -261,7 +267,10 @@ return(1); } + spin_lock(&devices_lock); list_add(&device->list, &devices); + spin_unlock(&devices_lock); + device->index = n; size = transport->private_size + sizeof(struct uml_net_private) + @@ -373,12 +382,16 @@ struct uml_net *device; struct list_head *ele; + spin_lock(&devices_lock); list_for_each(ele, &devices){ device = list_entry(ele, struct uml_net, list); if(device->index == n) - return(device); + goto out; } - return(NULL); + device = NULL; + out: + spin_unlock(&devices_lock); + return(device); } static int eth_parse(char *str, int *index_out, char **str_out) @@ -418,8 +431,12 @@ int index; }; +/* Filled in at boot time. Will need locking if the transports become + * modular. + */ struct list_head transports = LIST_HEAD_INIT(transports); +/* Filled in during early boot */ struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); static int check_transport(struct transport *transport, char *eth, int n, @@ -518,8 +535,6 @@ "eth[0-9]+=,\n" " Configure a network device.\n\n" ); - -int ndev = 0; static int eth_init(void) { diff -Nru a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c --- a/arch/um/drivers/port_kern.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/drivers/port_kern.c Tue Oct 15 20:29:12 2002 @@ -62,8 +62,6 @@ up(&conn->port->sem); } -struct list_head ports = LIST_HEAD_INIT(ports); - static void port_interrupt(int irq, void *data, struct pt_regs *regs) { struct port_list *port = data; @@ -107,6 +105,9 @@ reactivate_fd(port->fd, ACCEPT_IRQ); } +DECLARE_MUTEX(ports_sem); +struct list_head ports = LIST_HEAD_INIT(ports); + void *port_data(int port_num) { struct list_head *ele; @@ -114,6 +115,7 @@ struct port_dev *dev; int fd; + down(&ports_sem); list_for_each(ele, &ports){ port = list_entry(ele, struct port_list, list); if(port->port == port_num) goto found; @@ -121,7 +123,7 @@ port = kmalloc(sizeof(struct port_list), GFP_KERNEL); if(port == NULL){ printk(KERN_ERR "Allocation of port list failed\n"); - return(NULL); + goto out; } fd = port_listen_fd(port_num); @@ -151,18 +153,21 @@ dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL); if(dev == NULL){ printk(KERN_ERR "Allocation of port device entry failed\n"); - return(NULL); + goto out; } *dev = ((struct port_dev) { port : port, fd : -1, helper_pid : -1 }); + up(&ports_sem); return(dev); out_free: kfree(port); out_close: os_close_file(fd); + out: + up(&ports_sem); return(NULL); } @@ -184,7 +189,6 @@ list_for_each(ele, &ports){ port = list_entry(ele, struct port_list, list); - free_irq(ACCEPT_IRQ, port); os_close_file(port->fd); } } diff -Nru a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c --- a/arch/um/drivers/ssl.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/drivers/ssl.c Tue Oct 15 20:29:17 2002 @@ -24,10 +24,13 @@ static int ssl_version = 1; -static struct tty_driver ssl_driver; - +/* Referenced only by tty_driver below - presumably it's locked correctly + * by the tty driver. + */ static int ssl_refcount = 0; +static struct tty_driver ssl_driver; + #define NR_PORTS 64 void ssl_announce(char *dev_name, int dev) @@ -58,7 +61,10 @@ symlink_to : "tts", }; -static struct line serial_lines[NR_PORTS] = +/* The array is initialized by line_init, which is an initcall. The + * individual elements are protected by individual semaphores. + */ +static struct line serial_lines[NR_PORTS] = { [0 ... NR_PORTS - 1] = LINE_INIT(CONFIG_SSL_CHAN, &driver) }; static struct lines lines = LINES_INIT(NR_PORTS); @@ -153,6 +159,27 @@ { } +static struct tty_driver ssl_driver = { + refcount : &ssl_refcount, + open : ssl_open, + close : ssl_close, + write : ssl_write, + put_char : ssl_put_char, + flush_chars : ssl_flush_chars, + chars_in_buffer : ssl_chars_in_buffer, + flush_buffer : ssl_flush_buffer, + ioctl : ssl_ioctl, + throttle : ssl_throttle, + unthrottle : ssl_unthrottle, + set_termios : ssl_set_termios, + stop : ssl_stop, + start : ssl_start, + hangup : ssl_hangup +}; + +/* Changed by ssl_init and referenced by ssl_exit, which are both serialized + * by being an initcall and exitcall, respectively. + */ static int ssl_init_done = 0; int ssl_init(void) @@ -161,25 +188,6 @@ printk(KERN_INFO "Initializing software serial port version %d\n", ssl_version); - - ssl_driver = ((struct tty_driver) - { - refcount : &ssl_refcount, - open : ssl_open, - close : ssl_close, - write : ssl_write, - put_char : ssl_put_char, - flush_chars : ssl_flush_chars, - chars_in_buffer : ssl_chars_in_buffer, - flush_buffer : ssl_flush_buffer, - ioctl : ssl_ioctl, - throttle : ssl_throttle, - unthrottle : ssl_unthrottle, - set_termios : ssl_set_termios, - stop : ssl_stop, - start : ssl_start, - hangup : ssl_hangup - }); line_register_devfs(&lines, &driver, &ssl_driver, serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0])); diff -Nru a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c --- a/arch/um/drivers/stdio_console.c Tue Oct 15 20:29:14 2002 +++ b/arch/um/drivers/stdio_console.c Tue Oct 15 20:29:14 2002 @@ -32,8 +32,14 @@ #define MAX_TTYS (8) +/* Referenced only by tty_driver below - presumably it's locked correctly + * by the tty driver. + */ + static struct tty_driver console_driver; +static int console_refcount = 0; + static struct chan_ops init_console_ops = { init : NULL, open : NULL, @@ -88,6 +94,9 @@ static struct lines console_lines = LINES_INIT(MAX_TTYS); +/* The array is initialized by line_init, which is an initcall. The + * individual elements are protected by individual semaphores. + */ struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), [ 1 ... MAX_TTYS - 1 ] = LINE_INIT(CONFIG_CON_CHAN, &driver) }; @@ -130,15 +139,6 @@ printk(KERN_INFO "Initializing stdio console driver\n"); - console_driver = ((struct tty_driver) - { - open : con_open, - close : con_close, - write : con_write, - chars_in_buffer : chars_in_buffer, - set_termios : set_termios - }); - line_register_devfs(&console_lines, &driver, &console_driver, vts, sizeof(vts)/sizeof(vts[0])); @@ -157,9 +157,20 @@ static void console_write(struct console *console, const char *string, unsigned len) { + if(con_init_done) down(&vts[console->index].sem); console_write_chan(&vts[console->index].chan_list, string, len); + if(con_init_done) up(&vts[console->index].sem); } +static struct tty_driver console_driver = { + refcount : &console_refcount, + open : con_open, + close : con_close, + write : con_write, + chars_in_buffer : chars_in_buffer, + set_termios : set_termios +}; + static kdev_t console_device(struct console *c) { return mk_kdev(TTY_MAJOR, c->index); @@ -193,7 +204,6 @@ static void console_exit(void) { if(!con_init_done) return; - line_close(vts, NULL); close_lines(vts, sizeof(vts)/sizeof(vts[0])); } diff -Nru a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c --- a/arch/um/drivers/ubd_kern.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/drivers/ubd_kern.c Tue Oct 15 20:29:17 2002 @@ -25,6 +25,7 @@ #include "linux/vmalloc.h" #include "linux/blkpg.h" #include "linux/genhd.h" +#include "linux/spinlock.h" #include "asm/segment.h" #include "asm/uaccess.h" #include "asm/irq.h" @@ -41,7 +42,9 @@ #include "2_5compat.h" #include "os.h" -static spinlock_t ubd_lock; +static spinlock_t ubd_io_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED; + static void (*do_ubd)(void); static int ubd_open(struct inode * inode, struct file * filp); @@ -62,9 +65,12 @@ .revalidate = ubd_revalidate, }; +/* Protected by the queue_lock */ static request_queue_t *ubd_queue; +/* Protected by ubd_lock */ static int fake_major = 0; + static struct gendisk *ubd_gendisk[MAX_DEV]; static struct gendisk *fake_gendisk[MAX_DEV]; @@ -74,6 +80,9 @@ #define OPEN_FLAGS ((struct openflags) { .r = 1, .w = 1, .s = 0, .c = 0 }) #endif +/* Not protected - changed only in ubd_setup_common and then only to + * to enable O_SYNC. + */ static struct openflags global_openflags = OPEN_FLAGS; struct cow { @@ -130,12 +139,7 @@ __initcall(ubd0_init); -static struct hd_driveid ubd_id = { - .cyls = 0, - .heads = 128, - .sectors = 32, -}; - +/* Only changed by fake_ide_setup which is a setup */ static int fake_ide = 0; static struct proc_dir_entry *proc_ide_root = NULL; static struct proc_dir_entry *proc_ide = NULL; @@ -161,7 +165,6 @@ else len = count; *start = page + off; return len; - } static void make_ide_entries(char *dev_name) @@ -170,7 +173,9 @@ char name[64]; if(!fake_ide) return; + if(proc_ide_root == NULL) make_proc_ide(); + dir = proc_mkdir(dev_name, proc_ide); ent = create_proc_entry("media", S_IFREG|S_IRUGO, dir); if(!ent) return; @@ -199,7 +204,7 @@ { struct openflags flags = global_openflags; char *backing_file; - int n; + int n, err; if(index_out) *index_out = -1; n = *str++; @@ -224,12 +229,22 @@ return(1); } - fake_major = major; + err = 1; + spin_lock(&ubd_lock); + if(!fake_major_allowed){ + printk(KERN_ERR "Can't assign a fake major twice\n"); + goto out1; + } + + fake_major = major; fake_major_allowed = 0; printk(KERN_INFO "Setting extra ubd major number to %d\n", major); - return(0); + err = 0; + out1: + spin_unlock(&ubd_lock); + return(err); } if(n < '0'){ @@ -247,9 +262,12 @@ return(1); } + err = 1; + spin_lock(&ubd_lock); + if(ubd_dev[n].file != NULL){ printk(KERN_ERR "ubd_setup : device already configured\n"); - return(1); + goto out2; } if(index_out) *index_out = n; @@ -264,8 +282,10 @@ } if(*str++ != '='){ printk(KERN_ERR "ubd_setup : Expected '='\n"); - return(1); + goto out2; } + + err = 0; backing_file = strchr(str, ','); if(backing_file){ *backing_file = '\0'; @@ -276,7 +296,9 @@ ubd_dev[n].is_dir = 1; ubd_dev[n].cow.file = backing_file; ubd_dev[n].boot_openflags = flags; - return(0); + out2: + spin_unlock(&ubd_lock); + return(err); } static int ubd_setup(char *str) @@ -317,8 +339,12 @@ static void do_ubd_request(request_queue_t * q); +/* Only changed by ubd_init, which is an initcall. */ int thread_fd = -1; +/* Changed by ubd_handler, which is serialized because interrupts only + * happen on CPU 0. + */ int intr_count = 0; static void ubd_finish(int error) @@ -326,7 +352,9 @@ int nsect; if(error){ + spin_lock(&ubd_io_lock); end_request(CURRENT, 0); + spin_unlock(&ubd_io_lock); return; } nsect = CURRENT->current_nr_sectors; @@ -335,7 +363,9 @@ CURRENT->errors = 0; CURRENT->nr_sectors -= nsect; CURRENT->current_nr_sectors = 0; + spin_lock(&ubd_io_lock); end_request(CURRENT, 1); + spin_unlock(&ubd_io_lock); } static void ubd_handler(void) @@ -349,9 +379,9 @@ if(n != sizeof(req)){ printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " "errno = %d\n", os_getpid(), -n); - spin_lock(&ubd_lock); + spin_lock(&ubd_io_lock); end_request(CURRENT, 0); - spin_unlock(&ubd_lock); + spin_unlock(&ubd_io_lock); return; } @@ -359,11 +389,9 @@ (req.length != (CURRENT->current_nr_sectors) << 9)) panic("I/O op mismatch"); - spin_lock(&ubd_lock); ubd_finish(req.error); reactivate_fd(thread_fd, UBD_IRQ); do_ubd_request(ubd_queue); - spin_unlock(&ubd_lock); } static void ubd_intr(int irq, void *dev, struct pt_regs *unused) @@ -371,6 +399,7 @@ ubd_handler(); } +/* Only changed by ubd_init, which is an initcall. */ static int io_pid = -1; void kill_io_thread(void) @@ -380,8 +409,6 @@ __uml_exitcall(kill_io_thread); -int sync = 0; - static int ubd_file_size(struct ubd *dev, __u64 *size_out) { char *file; @@ -390,6 +417,7 @@ return(os_file_size(file, size_out)); } +/* Initialized in an initcall, and unchanged thereafter */ devfs_handle_t ubd_dir_handle; devfs_handle_t ubd_fake_dir_handle; @@ -402,14 +430,13 @@ u64 size; if (!dev->file) - return -1; + goto out; - disk = alloc_disk(); + disk = alloc_disk(1 << UBD_SHIFT); if (!disk) return -1; disk->major = MAJOR_NR; disk->first_minor = n << UBD_SHIFT; - disk->minor_shift = UBD_SHIFT; disk->fops = &ubd_blops; if (fakehd_set) sprintf(disk->disk_name, "hd%c", n + 'a'); @@ -417,14 +444,13 @@ sprintf(disk->disk_name, "ubd%d", n); if (fake_major) { - fake_disk = alloc_disk(); + fake_disk = alloc_disk(1 << UBD_SHIFT); if (!fake_disk) { put_disk(disk); return -1; } fake_disk->major = fake_major; fake_disk->first_minor = n << UBD_SHIFT; - fake_disk->minor_shift = UBD_SHIFT; fake_disk->fops = &ubd_blops; sprintf(fake_disk->disk_name, "ubd%d", n); fake_gendisk[n] = fake_disk; @@ -443,23 +469,32 @@ MAJOR_NR, n << UBD_SHIFT, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, &ubd_blops, NULL); - add_disk(disk); + if(real == NULL) + goto out; + ubd_dev[n].real = real; + if (fake_major) { fake = devfs_register(ubd_fake_dir_handle, name, DEVFS_FL_REMOVABLE, fake_major, n << UBD_SHIFT, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, &ubd_blops, NULL); - add_disk(fake_disk); - if(fake == NULL) return(-1); + if(fake == NULL) + goto out_unregister; + ubd_dev[n].fake = fake; + add_disk(fake_disk); } - if(real == NULL) return(-1); - ubd_dev[n].real = real; - + add_disk(disk); make_ide_entries(disk->disk_name); return(0); + + out_unregister: + devfs_unregister(real); + ubd_dev[n].real = NULL; + out: + return(-1); } static int ubd_config(char *str) @@ -478,24 +513,29 @@ } if(n == -1) return(0); + spin_lock(&ubd_lock); err = ubd_add(n); - if(err){ + if(err) ubd_dev[n].file = NULL; - return(err); - } + spin_unlock(&ubd_lock); - return(0); + return(err); } static int ubd_remove(char *str) { struct ubd *dev; - int n; + int n, err; - if(!isdigit(*str)) return(-1); + if(!isdigit(*str)) + return(-1); n = *str - '0'; - if(n > MAX_DEV) return(-1); + if(n > MAX_DEV) + return(-1); dev = &ubd_dev[n]; + + err = 0; + spin_lock(&ubd_lock); del_gendisk(ubd_gendisk[n]); put_disk(ubd_gendisk[n]); ubd_gendisk[n] = NULL; @@ -504,12 +544,20 @@ put_disk(fake_gendisk[n]); fake_gendisk[n] = NULL; } - if(dev->file == NULL) return(0); - if(dev->count > 0) return(-1); - if(dev->real != NULL) devfs_unregister(dev->real); - if(dev->fake != NULL) devfs_unregister(dev->fake); + if(dev->file == NULL) + goto out; + err = -1; + if(dev->count > 0) + goto out; + if(dev->real != NULL) + devfs_unregister(dev->real); + if(dev->fake != NULL) + devfs_unregister(dev->fake); *dev = ((struct ubd) DEFAULT_UBD); - return(0); + err = 0; + out: + spin_unlock(&ubd_lock); + return(err); } static struct mc_device ubd_mc = { @@ -541,7 +589,7 @@ return -1; } ubd_queue = BLK_DEFAULT_QUEUE(MAJOR_NR); - INIT_QUEUE(ubd_queue, do_ubd_request, &ubd_lock); + blk_init_queue(ubd_queue, do_ubd_request, &ubd_io_lock); elevator_init(ubd_queue, &elevator_noop); if(fake_major != 0){ char name[sizeof("ubd_nnn\0")]; @@ -566,7 +614,7 @@ unsigned long stack; int err; - if(sync){ + if(global_openflags.s){ printk(KERN_INFO "ubd : Synchronous mode\n"); return(0); } @@ -590,9 +638,9 @@ static void ubd_close(struct ubd *dev) { - close_fd(dev->fd); + os_close_file(dev->fd); if(dev->cow.file != NULL) { - close_fd(dev->cow.fd); + os_close_file(dev->cow.fd); vfree(dev->cow.bitmap); dev->cow.bitmap = NULL; } @@ -644,22 +692,17 @@ } return(0); error: - close_fd(dev->fd); + os_close_file(dev->fd); return(err); } static int ubd_open(struct inode *inode, struct file *filp) { - struct ubd *dev; - int n, offset, err; - - n = DEVICE_NR(inode->i_rdev); - dev = &ubd_dev[n]; - if(n > MAX_DEV) - return -ENODEV; - offset = n << UBD_SHIFT; + int n = DEVICE_NR(inode->i_rdev); + struct ubd *dev = &ubd_dev[n]; + int err; if(dev->is_dir == 1) - return(0); + goto out; if(dev->count == 0){ dev->openflags = dev->boot_openflags; @@ -668,36 +711,26 @@ if(err){ printk(KERN_ERR "ubd%d: Can't open \"%s\": " "errno = %d\n", n, dev->file, -err); - return(err); + goto out; } - if(err) return(err); } dev->count++; if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){ if(--dev->count == 0) ubd_close(dev); - return -EROFS; + err = -EROFS; } - return(0); + out: + return(err); } static int ubd_release(struct inode * inode, struct file * file) { - int n, offset; - - n = DEVICE_NR(inode->i_rdev); - offset = n << UBD_SHIFT; - if(n > MAX_DEV) - return -ENODEV; - + int n = DEVICE_NR(inode->i_rdev); if(--ubd_dev[n].count == 0) ubd_close(&ubd_dev[n]); - return(0); } -int cow_read = 0; -int cow_write = 0; - void cowify_req(struct io_thread_req *req, struct ubd *dev) { int i, update_bitmap, sector = req->offset >> 9; @@ -710,14 +743,12 @@ dev->cow.bitmap)){ ubd_set_bit(i, (unsigned char *) &req->sector_mask); - cow_read++; } } } else { update_bitmap = 0; for(i = 0; i < req->length >> 9; i++){ - cow_write++; ubd_set_bit(i, (unsigned char *) &req->sector_mask); if(!ubd_test_bit(sector + i, (unsigned char *) @@ -752,13 +783,17 @@ if(dev->is_dir){ strcpy(req->buffer, "HOSTFS:"); strcat(req->buffer, dev->file); + spin_lock(&ubd_io_lock); end_request(req, 1); + spin_unlock(&ubd_io_lock); return(1); } if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ printk("Write attempted on readonly ubd device %d\n", n); + spin_lock(&ubd_io_lock); end_request(req, 0); + spin_unlock(&ubd_io_lock); return(1); } @@ -819,6 +854,12 @@ struct hd_geometry *loc = (struct hd_geometry *) arg; struct ubd *dev; int n, min, err; + struct hd_driveid ubd_id = { + .cyls = 0, + .heads = 128, + .sectors = 32, + }; + if(!inode) return(-EINVAL); min = minor(inode->i_rdev); @@ -892,8 +933,11 @@ n = minor(rdev) >> UBD_SHIFT; dev = &ubd_dev[n]; + + err = 0; + spin_lock(&ubd_lock); if(dev->is_dir) - return(0); + goto out; err = ubd_file_size(dev, &size); if (!err) { @@ -902,7 +946,8 @@ set_capacity(fake_gendisk[n], size / 512); dev->size = size; } - + out: + spin_unlock(&ubd_lock); return err; } diff -Nru a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c --- a/arch/um/drivers/ubd_user.c Tue Oct 15 20:29:14 2002 +++ b/arch/um/drivers/ubd_user.c Tue Oct 15 20:29:14 2002 @@ -533,8 +533,12 @@ return; } +/* Changed in start_io_thread, which is serialized by being called only + * from ubd_init, which is an initcall. + */ int kernel_fd = -1; +/* Only changed by the io thread */ int io_count = 0; int io_thread(void *arg) diff -Nru a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c --- a/arch/um/drivers/xterm.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/drivers/xterm.c Tue Oct 15 20:29:12 2002 @@ -44,6 +44,7 @@ return(data); } +/* Only changed by xterm_setup, which is a setup */ static char *terminal_emulator = "xterm"; static char *title_switch = "-T"; static char *exec_switch = "-e"; diff -Nru a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h --- a/arch/um/include/2_5compat.h Tue Oct 15 20:29:16 2002 +++ b/arch/um/include/2_5compat.h Tue Oct 15 20:29:16 2002 @@ -20,8 +20,6 @@ next : NULL \ } -#define INIT_QUEUE(queue, request, lock) blk_init_queue(queue, request, lock) - #define INIT_HARDSECT(arr, maj, sizes) #define SET_PRI(task) do ; while(0) diff -Nru a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h --- a/arch/um/include/irq_user.h Tue Oct 15 20:29:17 2002 +++ b/arch/um/include/irq_user.h Tue Oct 15 20:29:17 2002 @@ -18,7 +18,9 @@ extern void init_irq_signals(int on_sigstack); extern void forward_ipi(int fd, int pid); extern void free_irq_later(int irq, void *dev_id); - +extern int activate_ipi(int fd, int pid); +extern unsigned long irq_lock(void); +extern void irq_unlock(unsigned long flags); #endif /* diff -Nru a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h --- a/arch/um/include/kern_util.h Tue Oct 15 20:29:16 2002 +++ b/arch/um/include/kern_util.h Tue Oct 15 20:29:16 2002 @@ -50,12 +50,8 @@ extern void block_signals(void); extern void unblock_signals(void); extern void deliver_signals(void *t); -extern void lock_syscall(void); -extern void unlock_syscall(void); -extern void lock_trap(void); -extern void unlock_trap(void); -extern void lock_pid(void); -extern void unlock_pid(void); +extern int next_syscall_index(int max); +extern int next_trap_index(int max); extern void default_idle(void); extern void finish_fork(void); extern void paging_init(void); @@ -121,7 +117,7 @@ extern int is_valid_pid(int pid); extern void free_irq(unsigned int, void *); extern int um_in_interrupt(void); - +extern int cpu(void); #endif /* diff -Nru a/arch/um/include/line.h b/arch/um/include/line.h --- a/arch/um/include/line.h Tue Oct 15 20:29:19 2002 +++ b/arch/um/include/line.h Tue Oct 15 20:29:19 2002 @@ -61,12 +61,9 @@ struct lines { int num; - int refcount; }; -#define LINES_INIT(n) \ - { num : n, \ - refcount : 0 } +#define LINES_INIT(n) { num : n } extern void line_interrupt(int irq, void *data, struct pt_regs *unused); extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused); diff -Nru a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h --- a/arch/um/include/mconsole.h Tue Oct 15 20:29:16 2002 +++ b/arch/um/include/mconsole.h Tue Oct 15 20:29:16 2002 @@ -77,6 +77,8 @@ extern int mconsole_notify(char *sock_name, int type, const void *data, int len); extern char *mconsole_notify_socket(void); +extern void lock_notify(void); +extern void unlock_notify(void); #endif diff -Nru a/arch/um/include/sigio.h b/arch/um/include/sigio.h --- a/arch/um/include/sigio.h Tue Oct 15 20:29:12 2002 +++ b/arch/um/include/sigio.h Tue Oct 15 20:29:12 2002 @@ -11,6 +11,8 @@ extern int read_sigio_fd(int fd); extern int add_sigio_fd(int fd, int read); extern int ignore_sigio_fd(int fd); +extern void sigio_lock(void); +extern void sigio_unlock(void); #endif diff -Nru a/arch/um/include/tempfile.h b/arch/um/include/tempfile.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/um/include/tempfile.h Tue Oct 15 20:29:23 2002 @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __TEMPFILE_H__ +#define __TEMPFILE_H__ + +extern int make_tempfile(const char *template, char **tempname, int do_unlink); + +#endif +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Nru a/arch/um/include/time_user.h b/arch/um/include/time_user.h --- a/arch/um/include/time_user.h Tue Oct 15 20:29:12 2002 +++ b/arch/um/include/time_user.h Tue Oct 15 20:29:12 2002 @@ -7,11 +7,11 @@ #define __TIME_USER_H__ extern void timer(void); -extern void get_profile_timer(void); -extern void disable_profile_timer(void); extern void switch_timers(int to_real); extern void user_time_init(void); -extern void set_timers(int set_signal); extern void idle_sleep(int secs); +extern void enable_timer(void); +extern void time_lock(void); +extern void time_unlock(void); #endif diff -Nru a/arch/um/include/user_util.h b/arch/um/include/user_util.h --- a/arch/um/include/user_util.h Tue Oct 15 20:29:12 2002 +++ b/arch/um/include/user_util.h Tue Oct 15 20:29:12 2002 @@ -48,32 +48,21 @@ extern int pty_output_sigio; extern int pty_close_sigio; -extern void *open_maps(void); -extern void close_maps(void *fd); -extern unsigned long get_brk(void); extern void stop(void); -extern int proc_start_thread(unsigned long ip, unsigned long sp); extern void stack_protections(unsigned long address); extern void task_protections(unsigned long address); -extern void abandon_proc_space(int (*proc)(void *), unsigned long sp); extern int signals(int (*init_proc)(void *), void *sp); -extern int __personality(int); extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); extern void *add_signal_handler(int sig, void (*handler)(int)); -extern void signal_init(void); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); extern void trace_myself(void); extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags); -extern int input_loop(void); -extern void continue_execing_proc(int pid); extern int linux_main(int argc, char **argv); extern void remap_data(void *segment_start, void *segment_end, int w); extern void set_cmdline(char *cmd); extern void input_cb(void (*proc)(void *), void *arg, int arg_len); -extern void setup_input(void); extern int get_pty(void); -extern void save_signal_state(int *sig_ptr); extern void *um_kmalloc(int size); extern int raw(int fd, int complain); extern int switcheroo(int fd, int prot, void *from, void *to, int size); @@ -82,15 +71,11 @@ extern void add_arg(char *cmd_line, char *arg); extern void init_new_thread(void *sig_stack, void (*usr1_handler)(int)); extern void attach_process(int pid); -extern void calc_sigframe_size(void); extern int fork_tramp(void *sig_stack); extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); -extern void close_fd(int); -extern int make_tempfile(const char *template, char **tempname, int do_unlink); extern char *get_umid(int only_if_set); extern void do_longjmp(void *p); -extern void term_handler(int sig); extern void suspend_new_thread(int fd); extern int detach(int pid, int sig); extern int attach(int pid); @@ -99,12 +84,9 @@ extern void check_ptrace(void); extern void check_sigio(void); extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); -extern int user_read(int fd, char *buf, int len); -extern int user_write(int fd, char *buf, int len); extern void write_sigio_workaround(void); extern void arch_check_bugs(void); extern int arch_handle_signal(int sig, struct uml_pt_regs *regs); -extern unsigned long pid_pc(int pid); extern int arch_fixup(unsigned long address, void *sc_ptr); extern void forward_pending_sigio(int target); diff -Nru a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile --- a/arch/um/kernel/Makefile Tue Oct 15 20:29:19 2002 +++ b/arch/um/kernel/Makefile Tue Oct 15 20:29:19 2002 @@ -3,9 +3,9 @@ obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \ helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ - process.o process_kern.o ptrace.o reboot.o resource.o setup.o \ - sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ - syscall_kern.o syscall_user.o sysrq.o sys_call_table.o time.o \ + process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ + sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \ + syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \ time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ umid.o user_util.o @@ -14,8 +14,8 @@ # user_syms.o not included here because Rules.make has its own ideas about # building anything in export-objs -USER_OBJS := $(filter %_user.o,$(obj-y)) config.o frame.o helper.o process.o \ - time.o tty_log.o umid.o user_util.o user_syms.o +USER_OBJS := $(filter %_user.o,$(obj-y)) config.o helper.o process.o \ + tempfile.o time.o tty_log.o umid.o user_util.o user_syms.o USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/kernel/$(file)) export-objs := ksyms.o process_kern.o signal_kern.o gprof_syms.o gmon_syms.o @@ -50,6 +50,9 @@ arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o ld -r -o $@ $< -lc -L/usr/lib + +arch/um/kernel/frame.o: arch/um/kernel/frame.c + $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $< QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while() { $$_ =~ s/CONFIG/$$config/; print $$_ }' diff -Nru a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c --- a/arch/um/kernel/exec_kern.c Tue Oct 15 20:29:15 2002 +++ b/arch/um/kernel/exec_kern.c Tue Oct 15 20:29:15 2002 @@ -17,6 +17,7 @@ #include "tlb.h" #include "2_5compat.h" #include "os.h" +#include "time_user.h" /* See comment above fork_tramp for why sigstop is defined and used like * this @@ -28,7 +29,6 @@ { int sig = sigstop; - block_signals(); init_new_thread(sig_stack, NULL); kill(os_getpid(), sig); return(0); @@ -62,6 +62,7 @@ unprotect_stack((unsigned long) current->thread_info); os_usr1_process(os_getpid()); + enable_timer(); free_page(stack); protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); task_protections((unsigned long) current->thread_info); diff -Nru a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c --- a/arch/um/kernel/exitcode.c Tue Oct 15 20:29:15 2002 +++ b/arch/um/kernel/exitcode.c Tue Oct 15 20:29:15 2002 @@ -8,6 +8,9 @@ #include "linux/proc_fs.h" #include "asm/uaccess.h" +/* If read and write race, the read will still atomically read a valid + * value. + */ int uml_exitcode = 0; static int read_proc_exitcode(char *page, char **start, off_t off, diff -Nru a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c --- a/arch/um/kernel/frame.c Tue Oct 15 20:29:16 2002 +++ b/arch/um/kernel/frame.c Tue Oct 15 20:29:16 2002 @@ -130,6 +130,7 @@ os_stop_process(os_getpid()); } +/* Changed only during early boot */ struct sc_frame signal_frame_sc; struct sc_frame_raw { @@ -142,6 +143,7 @@ struct arch_frame_data_raw arch; }; +/* Changed only during early boot */ static struct sc_frame_raw *raw_sc = NULL; static void sc_handler(int sig, struct sigcontext sc) @@ -163,6 +165,7 @@ return(-1); } +/* Changed only during early boot */ struct si_frame signal_frame_si; struct si_frame_raw { @@ -175,6 +178,7 @@ unsigned long sp; }; +/* Changed only during early boot */ static struct si_frame_raw *raw_si = NULL; static void si_handler(int sig, siginfo_t *si) diff -Nru a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c --- a/arch/um/kernel/helper.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/kernel/helper.c Tue Oct 15 20:29:17 2002 @@ -22,6 +22,7 @@ int fd; }; +/* Debugging aid, changed only from gdb */ int helper_pause = 0; static void helper_hup(int sig) diff -Nru a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd_kern.c --- a/arch/um/kernel/initrd_kern.c Tue Oct 15 20:29:11 2002 +++ b/arch/um/kernel/initrd_kern.c Tue Oct 15 20:29:11 2002 @@ -13,6 +13,7 @@ #include "init.h" #include "os.h" +/* Changed by uml_initrd_setup, which is a setup */ static char *initrd __initdata = NULL; static int __init read_initrd(void) diff -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c --- a/arch/um/kernel/irq.c Tue Oct 15 20:29:20 2002 +++ b/arch/um/kernel/irq.c Tue Oct 15 20:29:20 2002 @@ -78,6 +78,7 @@ end_none }; +/* Not changed */ volatile unsigned long irq_err_count; /* @@ -87,6 +88,7 @@ int get_irq_list(char *buf) { int i, j; + unsigned long flags; struct irqaction * action; char *p = buf; @@ -96,9 +98,10 @@ *p++ = '\n'; for (i = 0 ; i < NR_IRQS ; i++) { + spin_lock_irqsave(&irq_desc[i].lock, flags); action = irq_desc[i].action; if (!action) - continue; + goto end; p += sprintf(p, "%3d: ",i); #ifndef CONFIG_SMP p += sprintf(p, "%10u ", kstat_irqs(i)); @@ -113,6 +116,8 @@ for (action=action->next; action; action = action->next) p += sprintf(p, ", %s", action->name); *p++ = '\n'; + end: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); } p += sprintf(p, "\n"); #ifdef notdef @@ -548,11 +553,15 @@ } } +/* These are initialized by sysctl_init, which is called from init/main.c */ static struct proc_dir_entry * root_irq_dir; static struct proc_dir_entry * irq_dir [NR_IRQS]; static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; -unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +/* These are read and written as longs, so a read won't see a partial write + * even during a race. + */ +static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; #define HEX_DIGITS 8 @@ -679,6 +688,7 @@ smp_affinity_entry[irq] = entry; } +/* Read and written as a long */ unsigned long prof_cpu_mask = -1; void __init init_irq_proc (void) @@ -702,6 +712,21 @@ */ for (i = 0; i < NR_IRQS; i++) register_irq_proc(i); +} + +static spinlock_t irq_spinlock = SPIN_LOCK_UNLOCKED; + +unsigned long irq_lock(void) +{ + unsigned long flags; + + spin_lock_irqsave(&irq_spinlock, flags); + return(flags); +} + +void irq_unlock(unsigned long flags) +{ + spin_unlock_irqrestore(&irq_spinlock, flags); } unsigned long probe_irq_on(void) diff -Nru a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c --- a/arch/um/kernel/irq_user.c Tue Oct 15 20:29:16 2002 +++ b/arch/um/kernel/irq_user.c Tue Oct 15 20:29:16 2002 @@ -111,40 +111,20 @@ int activate_fd(int irq, int fd, int type, void *dev_id) { - struct irq_fd *new_fd; - int pid, retval, events, err; + struct pollfd *tmp_pfd; + struct irq_fd *new_fd, *irq_fd; + unsigned long flags; + int pid, events, err, n, size; + + pid = os_getpid(); + err = os_set_fd_async(fd, pid); + if(err < 0) + goto out; - for(new_fd = active_fds;new_fd;new_fd = new_fd->next){ - if((new_fd->fd == fd) && (new_fd->type == type)){ - printk("Registering fd %d twice\n", fd); - printk("Irqs : %d, %d\n", new_fd->irq, irq); - printk("Ids : 0x%x, 0x%x\n", new_fd->id, dev_id); - return(-EIO); - } - } - pid = cpu_tasks[0].pid; - if((retval = os_set_fd_async(fd, pid)) != 0) - return(retval); new_fd = um_kmalloc(sizeof(*new_fd)); err = -ENOMEM; - if(new_fd == NULL) return(err); - pollfds_num++; - if(pollfds_num > pollfds_size){ - struct pollfd *tmp_pfd; - - tmp_pfd = um_kmalloc(pollfds_num * sizeof(pollfds[0])); - if(tmp_pfd == NULL){ - pollfds_num--; - goto out_irq; - } - if(pollfds != NULL){ - memcpy(tmp_pfd, pollfds, - sizeof(pollfds[0]) * pollfds_size); - kfree(pollfds); - } - pollfds = tmp_pfd; - pollfds_size = pollfds_num; - } + if(new_fd == NULL) + goto out; if(type == IRQ_READ) events = POLLIN | POLLPRI; else events = POLLOUT; @@ -158,29 +138,90 @@ current_events: 0, freed : 0 } ); - *last_irq_ptr = new_fd; - last_irq_ptr = &new_fd->next; + /* Critical section - locked by a spinlock because this stuff can + * be changed from interrupt handlers. The stuff above is done + * outside the lock because it allocates memory. + */ + + /* Actually, it only looks like it can be called from interrupt + * context. The culprit is reactivate_fd, which calls + * maybe_sigio_broken, which calls write_sigio_workaround, + * which calls activate_fd. However, write_sigio_workaround should + * only be called once, at boot time. That would make it clear that + * this is called only from process context, and can be locked with + * a semaphore. + */ + flags = irq_lock(); + for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ + if((irq_fd->fd == fd) && (irq_fd->type == type)){ + printk("Registering fd %d twice\n", fd); + printk("Irqs : %d, %d\n", irq_fd->irq, irq); + printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id); + goto out_unlock; + } + } + + n = pollfds_num; + if(n == pollfds_size){ + while(1){ + /* Here we have to drop the lock in order to call + * kmalloc, which might sleep. If something else + * came in and changed the pollfds array, we free + * the buffer and try again. + */ + irq_unlock(flags); + size = (pollfds_num + 1) * sizeof(pollfds[0]); + tmp_pfd = um_kmalloc(size); + flags = irq_lock(); + if(tmp_pfd == NULL) + goto out_unlock; + if(n == pollfds_size) + break; + kfree(tmp_pfd); + } + if(pollfds != NULL){ + memcpy(tmp_pfd, pollfds, + sizeof(pollfds[0]) * pollfds_size); + kfree(pollfds); + } + pollfds = tmp_pfd; + pollfds_size++; + } if(type == IRQ_WRITE) events = 0; - pollfds[pollfds_num - 1] = ((struct pollfd) { fd : fd, - events : events, - revents : 0 }); + pollfds[pollfds_num] = ((struct pollfd) { fd : fd, + events : events, + revents : 0 }); + pollfds_num++; + + *last_irq_ptr = new_fd; + last_irq_ptr = &new_fd->next; + + irq_unlock(flags); + /* This calls activate_fd, so it has to be outside the critical + * section. + */ maybe_sigio_broken(fd, type); return(0); - out_irq: + out_unlock: + irq_unlock(flags); + out_free: kfree(new_fd); + out: return(err); } static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) { struct irq_fd **prev; + unsigned long flags; int i = 0; + flags = irq_lock(); prev = &active_fds; while(*prev != NULL){ if((*test)(*prev, arg)){ @@ -190,7 +231,7 @@ printk("free_irq_by_cb - mismatch between " "active_fds and pollfds, fd %d vs %d\n", (*prev)->fd, pollfds[i].fd); - return; + goto out; } memcpy(&pollfds[i], &pollfds[i + 1], (pollfds_num - i - 1) * sizeof(pollfds[0])); @@ -206,6 +247,8 @@ prev = &(*prev)->next; i++; } + out: + irq_unlock(flags); } struct irq_and_dev { @@ -242,29 +285,33 @@ { struct irq_fd *irq; int i = 0; - + for(irq=active_fds; irq != NULL; irq = irq->next){ if((irq->fd == fd) && (irq->irq == irqnum)) break; i++; } if(irq == NULL){ printk("find_irq_by_fd doesn't have descriptor %d\n", fd); - return(NULL); + goto out; } if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){ printk("find_irq_by_fd - mismatch between active_fds and " "pollfds, fd %d vs %d, need %d\n", irq->fd, pollfds[i].fd, fd); - return(NULL); + irq = NULL; + goto out; } *index_out = i; + out: return(irq); } void free_irq_later(int irq, void *dev_id) { struct irq_fd *irq_fd; + unsigned long flags; + flags = irq_lock(); for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ if((irq_fd->irq == irq) && (irq_fd->id == dev_id)) break; @@ -272,30 +319,48 @@ if(irq_fd == NULL){ printk("free_irq_later found no irq, irq = %d, " "dev_id = 0x%p\n", irq, dev_id); - return; + goto out; } irq_fd->freed = 1; + out: + irq_unlock(flags); } void reactivate_fd(int fd, int irqnum) { struct irq_fd *irq; + unsigned long flags; int i; + flags = irq_lock(); irq = find_irq_by_fd(fd, irqnum, &i); - if(irq == NULL) return; + if(irq == NULL){ + irq_unlock(flags); + return; + } pollfds[i].fd = irq->fd; + + irq_unlock(flags); + + /* This calls activate_fd, so it has to be outside the critical + * section. + */ maybe_sigio_broken(fd, irq->type); } void deactivate_fd(int fd, int irqnum) { struct irq_fd *irq; + unsigned long flags; int i; + flags = irq_lock(); irq = find_irq_by_fd(fd, irqnum, &i); - if(irq == NULL) return; + if(irq == NULL) + goto out; pollfds[i].fd = -1; + out: + irq_unlock(flags); } void forward_ipi(int fd, int pid) @@ -313,7 +378,9 @@ void forward_interrupts(int pid) { struct irq_fd *irq; + unsigned long flags; + flags = irq_lock(); for(irq=active_fds;irq != NULL;irq = irq->next){ if(fcntl(irq->fd, F_SETOWN, pid) < 0){ int save_errno = errno; @@ -328,6 +395,7 @@ } irq->pid = pid; } + irq_unlock(flags); } void init_irq_signals(int on_sigstack) @@ -339,10 +407,10 @@ if(timer_irq_inited) h = (__sighandler_t) alarm_handler; else h = boot_timer_handler; - set_handler(SIGVTALRM, h, flags | SA_NODEFER | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, -1); + set_handler(SIGVTALRM, h, flags | SA_RESTART, + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, - SIGUSR1, SIGIO, SIGWINCH, -1); + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); signal(SIGWINCH, SIG_IGN); } diff -Nru a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c --- a/arch/um/kernel/ksyms.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/kernel/ksyms.c Tue Oct 15 20:29:12 2002 @@ -20,6 +20,7 @@ EXPORT_SYMBOL(sys_waitpid); EXPORT_SYMBOL(task_size); EXPORT_SYMBOL(__do_copy_from_user); +EXPORT_SYMBOL(__do_copy_to_user); EXPORT_SYMBOL(__do_strncpy_from_user); EXPORT_SYMBOL(__do_strnlen_user); EXPORT_SYMBOL(flush_tlb_range); diff -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c --- a/arch/um/kernel/mem.c Tue Oct 15 20:29:16 2002 +++ b/arch/um/kernel/mem.c Tue Oct 15 20:29:16 2002 @@ -26,33 +26,32 @@ #include "kern.h" #include "init.h" +/* Changed during early boot */ +pgd_t swapper_pg_dir[1024]; unsigned long high_physmem; -unsigned long low_physmem; - unsigned long vm_start; unsigned long vm_end; - unsigned long highmem; - -pgd_t swapper_pg_dir[1024]; - unsigned long *empty_zero_page = NULL; - unsigned long *empty_bad_page = NULL; +/* Not modified */ const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; extern char __init_begin, __init_end; extern long physmem_size; +/* Not changed by UML */ mmu_gather_t mmu_gathers[NR_CPUS]; +/* Changed during early boot */ int kmalloc_ok = 0; #define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1) struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL }; #define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1) +/* Changed during early boot */ static unsigned long brk_end; static void map_cb(void *unused) @@ -108,6 +107,7 @@ } #if CONFIG_HIGHMEM +/* Changed during early boot */ pte_t *kmap_pte; pgprot_t kmap_prot; @@ -187,18 +187,22 @@ return(0); } +DECLARE_MUTEX(regions_sem); + static int setup_one_range(int fd, char *driver, unsigned long start, unsigned long pfn, int len, struct mem_region *region) { int i; + down(®ions_sem); for(i = 0; i < NREGIONS; i++){ if(regions[i] == NULL) break; } if(i == NREGIONS){ printk("setup_range : no free regions\n"); - return(-1); + i = -1; + goto out; } if(fd == -1) @@ -216,6 +220,8 @@ len : len, fd : fd } ); regions[i] = region; + out: + up(®ions_sem); return(i); } @@ -373,7 +379,8 @@ printk("%d pages swap cached\n", cached); } -unsigned long kmem_top = 0; +/* Changed during early boot */ +static unsigned long kmem_top = 0; unsigned long get_kmem_end(void) { @@ -428,8 +435,10 @@ goto again; } +DECLARE_MUTEX(vm_reserved_sem); static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved); +/* Static structures, linked in to the list in early boot */ static struct vm_reserved head = { list : LIST_HEAD_INIT(head.list), start : 0, @@ -455,7 +464,9 @@ { struct vm_reserved *entry = e, *reserved, *prev; struct list_head *ele; + int err; + down(&vm_reserved_sem); list_for_each(ele, &vm_reserved){ reserved = list_entry(ele, struct vm_reserved, list); if(reserved->start >= end) goto found; @@ -469,13 +480,17 @@ entry = kmalloc(sizeof(*entry), GFP_KERNEL); if(entry == NULL){ printk("reserve_vm : Failed to allocate entry\n"); - return(-ENOMEM); + err = -ENOMEM; + goto out; } *entry = ((struct vm_reserved) { list : LIST_HEAD_INIT(entry->list), start : start, end : end }); list_add(&entry->list, &prev->list); + err = 0; + out: + up(&vm_reserved_sem); return(0); } @@ -486,6 +501,7 @@ unsigned long start; int err; + down(&vm_reserved_sem); list_for_each(ele, &vm_reserved){ this = list_entry(ele, struct vm_reserved, list); next = list_entry(ele->next, struct vm_reserved, list); @@ -493,8 +509,10 @@ (this->end + len + PAGE_SIZE <= next->start)) goto found; } + up(&vm_reserved_sem); return(0); found: + up(&vm_reserved_sem); start = (unsigned long) ROUND_UP(this->end) + PAGE_SIZE; err = reserve_vm(start, start + len, NULL); if(err) return(0); @@ -533,7 +551,11 @@ unsigned long size; }; -struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = +/* iomem regions can only be added on the command line at the moment. + * Locking will be needed when they can be added via mconsole. + */ + +struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = { name : NULL, fd : -1, size : 0 } }; @@ -569,6 +591,7 @@ #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +/* Changed during early boot */ static struct mem_region physmem_region; static struct vm_reserved physmem_reserved; diff -Nru a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c --- a/arch/um/kernel/mem_user.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/kernel/mem_user.c Tue Oct 15 20:29:17 2002 @@ -46,10 +46,9 @@ #include "mem_user.h" #include "init.h" #include "os.h" +#include "tempfile.h" -struct mem_region physmem_region; - -struct mem_region *mem_list = &physmem_region; +extern struct mem_region physmem_region; #define TEMPNAME_TEMPLATE "vm_file-XXXXXX" diff -Nru a/arch/um/kernel/process.c b/arch/um/kernel/process.c --- a/arch/um/kernel/process.c Tue Oct 15 20:29:20 2002 +++ b/arch/um/kernel/process.c Tue Oct 15 20:29:20 2002 @@ -48,23 +48,23 @@ flags = SA_ONSTACK; } set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, -1); + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, -1); + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, -1); + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGILL, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, -1); + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, -1); + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, - SIGUSR1, SIGIO, SIGWINCH, -1); + SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, SA_NOMASK | flags, -1); if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); signal(SIGCHLD, SIG_IGN); signal(SIGHUP, SIG_IGN); - set_timers(1); /* XXX A bit of a race here */ + init_irq_signals(sig_stack != NULL); } diff -Nru a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c --- a/arch/um/kernel/process_kern.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/kernel/process_kern.c Tue Oct 15 20:29:17 2002 @@ -41,6 +41,10 @@ #include "2_5compat.h" #include "os.h" +/* This is a per-cpu array. A processor only modifies its entry and it only + * cares about its entry, so it's OK if another processor is modifying its + * entry. + */ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; struct task_struct *get_task(int pid, int require) @@ -86,7 +90,7 @@ { int i; - for(i = 0; i < num_online_cpus(); i++){ + for(i = 0; i < ncpus; i++){ if(cpu_tasks[i].pid == pid) return(i); } return(-1); @@ -152,12 +156,19 @@ current->thread.regs.regs.sc = (void *) (&sig + 1); suspend_new_thread(current->thread.switch_pipe[0]); + block_signals(); +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + enable_timer(); free_page(current->thread.temp_stack); set_cmdline("(kernel thread)"); force_flush_all(); current->thread.prev_sched = NULL; change_sig(SIGUSR1, 1); + change_sig(SIGVTALRM, 1); + change_sig(SIGPROF, 1); unblock_signals(); if(!run_kernel_thread(fn, arg, ¤t->thread.jmp)) do_exit(0); @@ -165,7 +176,9 @@ static int new_thread_proc(void *stack) { - block_signals(); + change_sig(SIGIO, 0); + change_sig(SIGVTALRM, 0); + change_sig(SIGPROF, 0); init_new_thread(stack, new_thread_handler); os_usr1_process(os_getpid()); return(0); @@ -204,6 +217,9 @@ unsigned long flags; int vtalrm, alrm, prof, err, cpu; char c; + /* jailing and SMP are incompatible, so this doesn't need to be + * made per-cpu + */ static int reading; from = prev; @@ -229,7 +245,7 @@ set_current(to); reading = 0; - err = user_write(to->thread.switch_pipe[1], &c, sizeof(c)); + err = os_write_file(to->thread.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, errno = %d", -err); @@ -237,7 +253,7 @@ if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) os_kill_process(os_getpid()); - err = user_read(from->thread.switch_pipe[0], &c, sizeof(c)); + err = os_read_file(from->thread.switch_pipe[0], &c, sizeof(c)); if(err != sizeof(c)) panic("read of switch_pipe failed, errno = %d", -err); @@ -298,13 +314,16 @@ * onto the signal frame. */ -extern int hit_me; - void finish_fork_handler(int sig) { current->thread.regs.regs.sc = (void *) (&sig + 1); suspend_new_thread(current->thread.switch_pipe[0]); - + +#ifdef CONFIG_SMP + schedule_tail(NULL); +#endif + enable_timer(); + change_sig(SIGVTALRM, 1); force_flush_all(); if(current->mm != current->parent->mm) protect(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); @@ -313,7 +332,6 @@ current->thread.prev_sched = NULL; free_page(current->thread.temp_stack); - block_signals(); change_sig(SIGUSR1, 0); set_user_mode(current); } @@ -339,7 +357,9 @@ { int sig = sigusr1; - block_signals(); + change_sig(SIGIO, 0); + change_sig(SIGVTALRM, 0); + change_sig(SIGPROF, 0); init_new_thread(stack, finish_fork_handler); kill(os_getpid(), sig); @@ -474,7 +494,7 @@ void default_idle(void) { - if(current->thread_info->cpu == 0) idle_timer(); + idle_timer(); atomic_inc(&init_mm.mm_count); current->mm = &init_mm; @@ -644,6 +664,7 @@ return(new); } +/* Changed by jail_setup, which is a setup */ int jail = 0; int __init jail_setup(char *line, int *add) @@ -708,17 +729,14 @@ mprotect_kernel_vm(w); } -int jail_timer_off = 0; - +/* No SMP problems since jailing and SMP are incompatible */ void unprotect_kernel_mem(void) { mprotect_kernel_mem(1); - jail_timer_off = 0; } void protect_kernel_mem(void) { - jail_timer_off = 1; mprotect_kernel_mem(0); } @@ -749,9 +767,11 @@ int smp_sigio_handler(void) { + int cpu = current->thread_info->cpu; #ifdef CONFIG_SMP - IPI_handler(hard_smp_processor_id()); - if (hard_smp_processor_id() != 0) return(1); + IPI_handler(cpu); + if(cpu != 0) + return(1); #endif return(0); } @@ -759,6 +779,11 @@ int um_in_interrupt(void) { return(in_interrupt()); +} + +int cpu(void) +{ + return(current->thread_info->cpu); } /* diff -Nru a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c --- a/arch/um/kernel/sigio_kern.c Tue Oct 15 20:29:14 2002 +++ b/arch/um/kernel/sigio_kern.c Tue Oct 15 20:29:14 2002 @@ -11,6 +11,7 @@ #include "sigio.h" #include "irq_user.h" +/* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; void sigio_interrupt(int irq, void *data, struct pt_regs *unused) @@ -29,6 +30,18 @@ } sigio_irq_fd = fd; return(0); +} + +static spinlock_t sigio_spinlock = SPIN_LOCK_UNLOCKED; + +void sigio_lock(void) +{ + spin_lock(&sigio_spinlock); +} + +void sigio_unlock(void) +{ + spin_unlock(&sigio_spinlock); } /* diff -Nru a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c --- a/arch/um/kernel/sigio_user.c Tue Oct 15 20:29:22 2002 +++ b/arch/um/kernel/sigio_user.c Tue Oct 15 20:29:22 2002 @@ -21,9 +21,11 @@ #include "helper.h" #include "os.h" +/* Changed during early boot */ int pty_output_sigio = 0; int pty_close_sigio = 0; +/* Used as a flag during SIGIO testing early in boot */ static int got_sigio = 0; void __init handler(int sig) @@ -151,7 +153,15 @@ check_one_sigio(tty_close); } +/* Protected by sigio_lock(), also used by sigio_cleanup, which is an + * exitcall. + */ static int write_sigio_pid = -1; + +/* These arrays are initialized before the sigio thread is started, and + * the descriptors closed after it is killed. So, it can't see them change. + * On the UML side, they are changed under the sigio_lock. + */ static int write_sigio_fds[2] = { -1, -1 }; static int sigio_private[2] = { -1, -1 }; @@ -161,6 +171,9 @@ int used; }; +/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread + * synchronizes with it. + */ struct pollfds current_poll = { poll : NULL, size : 0, @@ -217,8 +230,6 @@ } } -/* XXX SMP locking needed here too */ - static int need_poll(int n) { if(n <= next_poll.size){ @@ -260,25 +271,31 @@ set_signals(flags); return; fail: + sigio_lock(); if(write_sigio_pid != -1) kill(write_sigio_pid, SIGKILL); write_sigio_pid = -1; close(sigio_private[0]); close(sigio_private[1]); close(write_sigio_fds[0]); close(write_sigio_fds[1]); + sigio_unlock(); set_signals(flags); } int add_sigio_fd(int fd, int read) { - int err, i, n, events; + int err = 0, i, n, events; - for(i = 0; i < current_poll.used; i++) - if(current_poll.poll[i].fd == fd) return(0); + sigio_lock(); + for(i = 0; i < current_poll.used; i++){ + if(current_poll.poll[i].fd == fd) + goto out; + } n = current_poll.used + 1; err = need_poll(n); - if(err) return(err); + if(err) + goto out; for(i = 0; i < current_poll.used; i++) next_poll.poll[i] = current_poll.poll[i]; @@ -290,21 +307,26 @@ events : events, revents : 0 }); update_thread(); - return(0); + out: + sigio_unlock(); + return(err); } int ignore_sigio_fd(int fd) { struct pollfd *p; - int err, i, n = 0; + int err = 0, i, n = 0; + sigio_lock(); for(i = 0; i < current_poll.used; i++){ if(current_poll.poll[i].fd == fd) break; } - if(i == current_poll.used) return(0); + if(i == current_poll.used) + goto out; err = need_poll(current_poll.used - 1); - if(err) return(err); + if(err) + goto out; for(i = 0; i < current_poll.used; i++){ p = ¤t_poll.poll[i]; @@ -312,11 +334,14 @@ } if(n == i){ printk("ignore_sigio_fd : fd %d not found\n", fd); - return(-1); + err = -1; + goto out; } update_thread(); - return(0); + out: + sigio_unlock(); + return(err); } static int setup_initial_poll(int fd) @@ -342,14 +367,15 @@ unsigned long stack; int err; - if(write_sigio_pid != -1) return; + sigio_lock(); + if(write_sigio_pid != -1) + goto out; - /* XXX This needs SMP locking */ err = os_pipe(write_sigio_fds, 1, 1); if(err){ printk("write_sigio_workaround - os_pipe 1 failed, " "errno = %d\n", -err); - return; + goto out; } err = os_pipe(sigio_private, 1, 1); if(err){ @@ -368,6 +394,8 @@ if(write_sigio_irq(write_sigio_fds[0])) goto out_kill; + out: + sigio_unlock(); return; out_kill: @@ -379,6 +407,7 @@ out_close1: close(write_sigio_fds[0]); close(write_sigio_fds[1]); + sigio_unlock(); } int read_sigio_fd(int fd) diff -Nru a/arch/um/kernel/signal_user.c b/arch/um/kernel/signal_user.c --- a/arch/um/kernel/signal_user.c Tue Oct 15 20:29:19 2002 +++ b/arch/um/kernel/signal_user.c Tue Oct 15 20:29:19 2002 @@ -19,8 +19,6 @@ #include "sysdep/sigcontext.h" #include "sigcontext.h" -extern int kern_timer_on; - void set_sigstack(void *sig_stack, int size) { stack_t stack; @@ -57,7 +55,7 @@ sigemptyset(&sigset); sigaddset(&sigset, signal); sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); - return(sigismember(&old, signal)); + return(!sigismember(&old, signal)); } static void change_signals(int type) @@ -65,12 +63,8 @@ sigset_t mask; sigemptyset(&mask); - if(type == SIG_BLOCK) kern_timer_on = 0; - else { - kern_timer_on = 1; - sigaddset(&mask, SIGVTALRM); - sigaddset(&mask, SIGALRM); - } + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); sigaddset(&mask, SIGIO); sigaddset(&mask, SIGPROF); if(sigprocmask(type, &mask, NULL) < 0) @@ -97,7 +91,6 @@ sigs = sigismember(mask, SIGIO) ? 1 << SIGIO_BIT : 0; sigs |= sigismember(mask, SIGVTALRM) ? 1 << SIGVTALRM_BIT : 0; sigs |= sigismember(mask, SIGALRM) ? 1 << SIGVTALRM_BIT : 0; - if(!kern_timer_on) sigs |= 1 << SIGVTALRM_BIT; return(sigs); } @@ -116,21 +109,27 @@ int ret; sigemptyset(&mask); - if(!(disable & (1 << SIGIO_BIT))) sigaddset(&mask, SIGIO); + if(!(disable & (1 << SIGIO_BIT))) + sigaddset(&mask, SIGIO); if(!(disable & (1 << SIGVTALRM_BIT))){ - kern_timer_on = 1; sigaddset(&mask, SIGVTALRM); sigaddset(&mask, SIGALRM); } if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) panic("Failed to enable signals"); + ret = disable_mask(&mask); + sigemptyset(&mask); - if(disable & (1 << SIGIO_BIT)) sigaddset(&mask, SIGIO); - if(disable & (1 << SIGVTALRM_BIT)) - kern_timer_on = 0; + if(disable & (1 << SIGIO_BIT)) + sigaddset(&mask, SIGIO); + if(disable & (1 << SIGVTALRM_BIT)){ + sigaddset(&mask, SIGVTALRM); + sigaddset(&mask, SIGALRM); + } if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) panic("Failed to block signals"); + return(ret); } diff -Nru a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c --- a/arch/um/kernel/smp.c Tue Oct 15 20:29:13 2002 +++ b/arch/um/kernel/smp.c Tue Oct 15 20:29:13 2002 @@ -5,7 +5,7 @@ #include "linux/config.h" -/* CPU online map */ +/* CPU online map, set by smp_boot_cpus */ unsigned long cpu_online_map = 1; #ifdef CONFIG_SMP @@ -21,25 +21,32 @@ #include "user_util.h" #include "kern_util.h" #include "kern.h" +#include "irq_user.h" #include "os.h" -/* The 'big kernel lock' */ -spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; - -/* Per CPU bogomips and other parameters */ +/* Per CPU bogomips and other parameters + * The only piece used here is the ipi pipe, which is set before SMP is + * started and never changed. + */ struct cpuinfo_um cpu_data[NR_CPUS]; spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED; atomic_t global_bh_count; +/* Not used by UML */ unsigned char global_irq_holder = NO_PROC_ID; unsigned volatile long global_irq_lock; /* Set when the idlers are all forked */ int smp_threads_ready = 0; + +/* A statistic, can be a little off */ int num_reschedules_sent = 0; +/* Small, random number, never changed */ +unsigned long cache_decay_ticks = 5; + void smp_send_reschedule(int cpu) { write(cpu_data[cpu].ipi_pipe[1], "R", 1); @@ -83,30 +90,24 @@ void smp_send_stop(void) { - printk(KERN_INFO "Stopping all CPUs\n"); -} + int i; + printk(KERN_INFO "Stopping all CPUs..."); + for(i = 0; i < num_online_cpus(); i++){ + if(i == current->thread_info->cpu) + continue; + write(cpu_data[i].ipi_pipe[1], "S", 1); + } + printk("done\n"); +} -static atomic_t smp_commenced = ATOMIC_INIT(0); +static unsigned long smp_commenced_mask; static volatile unsigned long smp_callin_map = 0; -void smp_commence(void) +static int idle_proc(void *cpup) { - printk("All CPUs are go!\n"); - - wmb(); - atomic_set(&smp_commenced, 1); -} - -static int idle_proc(void *unused) -{ - int cpu, err; - - set_current(current); - del_from_runqueue(current); - unhash_process(current); + int cpu = (int) cpup, err; - cpu = current->processor; err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1); if(err) panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, @@ -115,46 +116,41 @@ activate_ipi(cpu_data[cpu].ipi_pipe[0], current->thread.extern_pid); wmb(); - if (test_and_set_bit(current->processor, &smp_callin_map)) { - printk("huh, CPU#%d already present??\n", current->processor); + if (test_and_set_bit(cpu, &smp_callin_map)) { + printk("huh, CPU#%d already present??\n", cpu); BUG(); } - while (!atomic_read(&smp_commenced)) + while (!test_bit(cpu, &smp_commenced_mask)) cpu_relax(); - init_idle(); + set_bit(cpu, &cpu_online_map); default_idle(); return(0); } -int inited_cpus = 1; - -static int idle_thread(int (*fn)(void *), int cpu) +static struct task_struct *idle_thread(int cpu) { - struct task_struct *p; - int pid; + struct task_struct *new_task; unsigned char c; - current->thread.request.u.thread.proc = fn; - current->thread.request.u.thread.arg = NULL; - p = do_fork(CLONE_VM | CLONE_PID, 0, NULL, 0); - if(IS_ERR(p)) panic("do_fork failed in idle_thread"); - - cpu_tasks[cpu].pid = p->thread.extern_pid; - cpu_tasks[cpu].task = p; - inited_cpus++; - init_tasks[cpu] = p; - p->processor = cpu; - p->cpus_allowed = 1 << cpu; - p->cpus_runnable = p->cpus_allowed; - write(p->thread.switch_pipe[1], &c, sizeof(c)); - return(p->thread.extern_pid); -} - -void smp_boot_cpus(void) -{ - int err; + current->thread.request.u.thread.proc = idle_proc; + current->thread.request.u.thread.arg = (void *) cpu; + new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL); + if(IS_ERR(new_task)) panic("do_fork failed in idle_thread"); + + cpu_tasks[cpu] = ((struct cpu_task) + { .pid = new_task->thread.extern_pid, + .task = new_task } ); + write(new_task->thread.switch_pipe[1], &c, sizeof(c)); + return(new_task); +} + +void smp_prepare_cpus(unsigned int maxcpus) +{ + struct task_struct *idle; + unsigned long waittime; + int err, cpu; set_bit(0, &cpu_online_map); set_bit(0, &smp_callin_map); @@ -164,44 +160,30 @@ activate_ipi(cpu_data[0].ipi_pipe[0], current->thread.extern_pid); - if(ncpus < 1){ - printk(KERN_INFO "ncpus set to 1\n"); - ncpus = 1; + for(cpu = 1; cpu < ncpus; cpu++){ + printk("Booting processor %d...\n", cpu); + + idle = idle_thread(cpu); + + init_idle(idle, cpu); + unhash_process(idle); + + waittime = 200000000; + while (waittime-- && !test_bit(cpu, &smp_callin_map)) + cpu_relax(); + + if (test_bit(cpu, &smp_callin_map)) + printk("done\n"); + else printk("failed\n"); } - else if(ncpus > NR_CPUS){ - printk(KERN_INFO - "ncpus can't be greater than NR_CPUS, set to %d\n", - NR_CPUS); - ncpus = NR_CPUS; - } - - if(ncpus > 1){ - int i, pid; +} - printk(KERN_INFO "Starting up other processors:\n"); - for(i=1;ineed_resched = 1; + set_tsk_need_resched(current); + break; + + case 'S': + printk("CPU#%d stopping\n", cpu); + while(1) + pause(); break; default: @@ -269,7 +257,8 @@ info = _info; for (i=0;iprocessor && test_bit(i, &cpu_online_map)) + if((i != current->thread_info->cpu) && + test_bit(i, &cpu_online_map)) write(cpu_data[i].ipi_pipe[1], "C", 1); while (atomic_read(&scf_started) != cpus) diff -Nru a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c --- a/arch/um/kernel/syscall_kern.c Tue Oct 15 20:29:19 2002 +++ b/arch/um/kernel/syscall_kern.c Tue Oct 15 20:29:19 2002 @@ -384,6 +384,7 @@ return(0); } +/* Unlocked, I don't care if this is a bit off */ int nsyscalls = 0; extern syscall_handler_t *sys_call_table[]; @@ -417,14 +418,18 @@ spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED; -void lock_syscall(void) -{ - spin_lock(&syscall_lock); -} +static int syscall_index = 0; -void unlock_syscall(void) +int next_syscall_index(int limit) { + int ret; + + spin_lock(&syscall_lock); + ret = syscall_index; + if(++syscall_index == limit) + syscall_index = 0; spin_unlock(&syscall_lock); + return(ret); } /* diff -Nru a/arch/um/kernel/syscall_user.c b/arch/um/kernel/syscall_user.c --- a/arch/um/kernel/syscall_user.c Tue Oct 15 20:29:13 2002 +++ b/arch/um/kernel/syscall_user.c Tue Oct 15 20:29:13 2002 @@ -34,21 +34,14 @@ struct timeval end; } syscall_record[1024]; -int syscall_index = 0; - -extern int kern_timer_on; - void syscall_handler(int sig, struct uml_pt_regs *regs) { void *sc; long result; - int index, syscall; + int index, max, syscall; - lock_syscall(); - if(syscall_index == 1024) syscall_index = 0; - index = syscall_index; - syscall_index++; - unlock_syscall(); + max = sizeof(syscall_record)/sizeof(syscall_record[0]); + index = next_syscall_index(max); syscall = regs->syscall; sc = regs->sc; diff -Nru a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/um/kernel/tempfile.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include +#include +#include +#include +#include +#include +#include "init.h" + +char *tempdir = NULL; + +static void __init find_tempdir(void) +{ + char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; + int i; + char *dir = NULL; + + if(tempdir != NULL) return; /* We've already been called */ + for(i = 0; dirs[i]; i++){ + dir = getenv(dirs[i]); + if(dir != NULL) break; + } + if(dir == NULL) dir = "/tmp"; + else if(*dir == '\0') dir = NULL; + if(dir != NULL) { + tempdir = malloc(strlen(dir) + 2); + if(tempdir == NULL){ + fprintf(stderr, "Failed to malloc tempdir, " + "errno = %d\n", errno); + return; + } + strcpy(tempdir, dir); + strcat(tempdir, "/"); + } +} + +int make_tempfile(const char *template, char **out_tempname, int do_unlink) +{ + char tempname[MAXPATHLEN]; + int fd; + + find_tempdir(); + if (*template != '/') + strcpy(tempname, tempdir); + else + *tempname = 0; + strcat(tempname, template); + if((fd = mkstemp(tempname)) < 0){ + fprintf(stderr, "open - cannot create %s: %s\n", tempname, + strerror(errno)); + return -1; + } + if(do_unlink && (unlink(tempname) < 0)){ + perror("unlink"); + return -1; + } + if(out_tempname){ + if((*out_tempname = strdup(tempname)) == NULL){ + perror("strdup"); + return -1; + } + } + return(fd); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -Nru a/arch/um/kernel/time.c b/arch/um/kernel/time.c --- a/arch/um/kernel/time.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/kernel/time.c Tue Oct 15 20:29:12 2002 @@ -14,33 +14,15 @@ #include "user.h" #include "process.h" #include "signal_user.h" +#include "time_user.h" extern struct timeval xtime; -void timer_handler(int sig, struct uml_pt_regs *regs) -{ - timer_irq(regs); -} - void timer(void) { gettimeofday(&xtime, NULL); } -static struct itimerval profile_interval; - -void get_profile_timer(void) -{ - getitimer(ITIMER_PROF, &profile_interval); - profile_interval.it_value = profile_interval.it_interval; -} - -void disable_profile_timer(void) -{ - struct itimerval interval = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); - setitimer(ITIMER_PROF, &interval, NULL); -} - static void set_interval(int timer_type) { struct itimerval interval; @@ -53,6 +35,15 @@ panic("setitimer failed - errno = %d\n", errno); } +void enable_timer(void) +{ + struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, + { 0, 1000000/hz() }}); + if(setitimer(ITIMER_VIRTUAL, &enable, NULL)) + printk("enable_timer - setitimer failed, errno = %d\n", + errno); +} + void switch_timers(int to_real) { struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); @@ -79,8 +70,9 @@ { if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) panic("Couldn't unset SIGVTALRM handler"); + set_handler(SIGALRM, (__sighandler_t) alarm_handler, - SA_NODEFER | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, -1); + SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); set_interval(ITIMER_REAL); } @@ -98,28 +90,24 @@ set_interval(ITIMER_VIRTUAL); } -void set_timers(int set_signal) -{ - if(set_signal) - set_interval(ITIMER_VIRTUAL); - if(setitimer(ITIMER_PROF, &profile_interval, NULL) == -1) - panic("setitimer ITIMER_PROF failed - errno = %d\n", errno); -} - struct timeval local_offset = { 0, 0 }; void do_gettimeofday(struct timeval *tv) { + time_lock(); gettimeofday(tv, NULL); timeradd(tv, &local_offset, tv); + time_unlock(); } void do_settimeofday(struct timeval *tv) { struct timeval now; + time_lock(); gettimeofday(&now, NULL); timersub(tv, &now, &local_offset); + time_unlock(); } void idle_sleep(int secs) diff -Nru a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c --- a/arch/um/kernel/time_kern.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/kernel/time_kern.c Tue Oct 15 20:29:17 2002 @@ -27,21 +27,21 @@ return(HZ); } +/* Changed at early boot */ int timer_irq_inited = 0; -/* kern_timer_on and missed_ticks are modified after kernel memory has been +/* missed_ticks will be modified after kernel memory has been * write-protected, so this puts it in a section which will be left * write-enabled. */ -int __attribute__ ((__section__ (".unprotected"))) kern_timer_on = 0; -int __attribute__ ((__section__ (".unprotected"))) missed_ticks = 0; +int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS]; void timer_irq(struct uml_pt_regs *regs) { - int ticks = missed_ticks; + int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu]; if(!timer_irq_inited) return; - missed_ticks = 0; + missed_ticks[cpu] = 0; while(ticks--) do_IRQ(TIMER_IRQ, regs); } @@ -86,6 +86,7 @@ return 0; } +/* XXX Needs to be moved under sys-i386 */ void __delay(um_udelay_t time) { /* Stolen from the i386 __loop_delay */ @@ -114,6 +115,27 @@ n = (loops_per_jiffy * HZ * usecs) / 1000000; for(i=0;ithread_info->cpu == 0) + timer_irq(regs); +} + +static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED; + +void time_lock(void) +{ + spin_lock(&timer_spinlock); +} + +void time_unlock(void) +{ + spin_unlock(&timer_spinlock); } int __init timer_init(void) diff -Nru a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c --- a/arch/um/kernel/trap_kern.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/kernel/trap_kern.c Tue Oct 15 20:29:12 2002 @@ -171,14 +171,18 @@ spinlock_t trap_lock = SPIN_LOCK_UNLOCKED; -void lock_trap(void) -{ - spin_lock(&trap_lock); -} +static int trap_index = 0; -void unlock_trap(void) +int next_trap_index(int limit) { + int ret; + + spin_lock(&trap_lock); + ret = trap_index; + if(++trap_index == limit) + trap_index = 0; spin_unlock(&trap_lock); + return(ret); } extern int debugger_pid; @@ -209,6 +213,7 @@ tramp_stack : 0, }; +/* Accessed by the tracing thread, which automatically serializes access */ static void *xterm_data; static int xterm_fd; diff -Nru a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c --- a/arch/um/kernel/trap_user.c Tue Oct 15 20:29:16 2002 +++ b/arch/um/kernel/trap_user.c Tue Oct 15 20:29:16 2002 @@ -70,10 +70,10 @@ while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT); } +/* Changed early in boot, and then only read */ int debug = 0; int debug_stop = 1; int debug_parent = 0; - int honeypot = 0; static int signal_tramp(void *arg) @@ -90,7 +90,6 @@ signal(SIGUSR1, SIG_IGN); change_sig(SIGCHLD, 0); signal(SIGSEGV, (__sighandler_t) sig_handler); - set_timers(0); set_cmdline("(idle thread)"); set_init_pid(os_getpid()); proc = arg; @@ -99,6 +98,7 @@ static void last_ditch_exit(int sig) { + kmalloc_ok = 0; signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGHUP, SIG_DFL); @@ -142,33 +142,20 @@ } } -#ifdef CONFIG_SMP -#error need to make these arrays -#endif - +/* Accessed only by the tracing thread */ int debugger_pid = -1; int debugger_parent = -1; int debugger_fd = -1; int gdb_pid = -1; struct { - unsigned long address; - int is_write; - int pid; - unsigned long sp; - int is_user; -} segfault_record[1024]; - -int segfault_index = 0; - -struct { int pid; int signal; unsigned long addr; struct timeval time; -} signal_record[1024]; +} signal_record[1024][32]; -int signal_index = 0; +int signal_index[32]; int nsignals = 0; int debug_trace = 0; extern int io_nsignals, io_count, intr_count; @@ -188,7 +175,7 @@ signal(SIGPIPE, SIG_IGN); setup_tracer_winch(); tracing_pid = os_getpid(); - printk("tracing thread pid = %d\n", tracing_pid); + printf("tracing thread pid = %d\n", tracing_pid); pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); n = waitpid(pid, &status, WUNTRACED); @@ -207,7 +194,7 @@ set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); if(debug_trace){ - printk("Tracing thread pausing to be attached\n"); + printf("Tracing thread pausing to be attached\n"); stop(); } if(debug){ @@ -219,14 +206,14 @@ init_parent_proxy(debugger_parent); err = attach(debugger_parent); if(err){ - printk("Failed to attach debugger parent %d, " + printf("Failed to attach debugger parent %d, " "errno = %d\n", debugger_parent, err); debugger_parent = -1; } else { if(ptrace(PTRACE_SYSCALL, debugger_parent, 0, 0) < 0){ - printk("Failed to continue debugger " + printf("Failed to continue debugger " "parent, errno = %d\n", errno); debugger_parent = -1; } @@ -237,7 +224,7 @@ while(1){ if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){ if(errno != ECHILD){ - printk("wait failed - errno = %d\n", errno); + printf("wait failed - errno = %d\n", errno); } continue; } @@ -259,36 +246,36 @@ if(WIFEXITED(status)) ; #ifdef notdef { - printk("Child %d exited with status %d\n", pid, + printf("Child %d exited with status %d\n", pid, WEXITSTATUS(status)); } #endif else if(WIFSIGNALED(status)){ sig = WTERMSIG(status); if(sig != 9){ - printk("Child %d exited with signal %d\n", pid, + printf("Child %d exited with signal %d\n", pid, sig); } } else if(WIFSTOPPED(status)){ + proc_id = pid_to_processor_id(pid); sig = WSTOPSIG(status); - if(signal_index == 1024){ - signal_index = 0; + if(signal_index[proc_id] == 1024){ + signal_index[proc_id] = 0; last_index = 1023; } - else last_index = signal_index - 1; + else last_index = signal_index[proc_id] - 1; if(((sig == SIGPROF) || (sig == SIGVTALRM) || (sig == SIGALRM)) && - (signal_record[last_index].signal == sig) && - (signal_record[last_index].pid == pid)) - signal_index = last_index; - signal_record[signal_index].pid = pid; - gettimeofday(&signal_record[signal_index].time, NULL); + (signal_record[proc_id][last_index].signal == sig)&& + (signal_record[proc_id][last_index].pid == pid)) + signal_index[proc_id] = last_index; + signal_record[proc_id][signal_index[proc_id]].pid = pid; + gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL); eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); - signal_record[signal_index].addr = eip; - signal_record[signal_index++].signal = sig; + signal_record[proc_id][signal_index[proc_id]].addr = eip; + signal_record[proc_id][signal_index[proc_id]++].signal = sig; - proc_id = pid_to_processor_id(pid); if(proc_id == -1){ sleeping_process_signal(pid, sig); continue; @@ -314,7 +301,7 @@ ptrace(PTRACE_KILL, pid, 0, 0); return(op == OP_REBOOT); case OP_NONE: - printk("Detaching pid %d\n", pid); + printf("Detaching pid %d\n", pid); detach(pid, SIGSTOP); continue; default: @@ -413,22 +400,30 @@ " UML. This implies 'jail'.\n\n" ); +/* Unlocked - don't care if this is a bit off */ int nsegfaults = 0; +struct { + unsigned long address; + int is_write; + int pid; + unsigned long sp; + int is_user; +} segfault_record[1024]; + void segv_handler(int sig, struct uml_pt_regs *regs) { struct sigcontext *context = regs->sc; - int index; + int index, max; if(regs->is_user && !SEGV_IS_FIXABLE(context)){ bad_segv(SC_FAULT_ADDR(context), SC_IP(context), SC_FAULT_WRITE(context)); return; } - lock_trap(); - index = segfault_index++; - if(segfault_index == 1024) segfault_index = 0; - unlock_trap(); + max = sizeof(segfault_record)/sizeof(segfault_record[0]); + index = next_trap_index(max); + nsegfaults++; segfault_record[index].address = SC_FAULT_ADDR(context); segfault_record[index].pid = os_getpid(); @@ -439,8 +434,6 @@ regs->is_user, context); } -extern int kern_timer_on; - struct signal_info { void (*handler)(int, struct uml_pt_regs *); int is_irq; @@ -471,7 +464,7 @@ { struct uml_pt_regs save_regs, *r; struct signal_info *info; - int save_errno = errno, save_timer = kern_timer_on, is_user; + int save_errno = errno, is_user; unprotect_kernel_mem(); @@ -488,7 +481,6 @@ (*info->handler)(sig, r); - kern_timer_on = save_timer; if(is_user){ interrupt_end(); block_signals(); @@ -505,19 +497,15 @@ sig_handler_common(sig, &sc); } -extern int timer_irq_inited, missed_ticks; - -extern int jail_timer_off; +extern int timer_irq_inited, missed_ticks[]; void alarm_handler(int sig, struct sigcontext sc) { int user; if(!timer_irq_inited) return; - missed_ticks++; + missed_ticks[cpu()]++; user = user_context(SC_SP(&sc)); - if(!user && !kern_timer_on) return; - if(!user && jail_timer_off) return; if(sig == SIGALRM) switch_timers(0); diff -Nru a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c --- a/arch/um/kernel/tty_log.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/kernel/tty_log.c Tue Oct 15 20:29:17 2002 @@ -17,8 +17,8 @@ #define TTY_LOG_DIR "./" -char *tty_log_dir = TTY_LOG_DIR; - +/* Set early in boot and then unchanged */ +static char *tty_log_dir = TTY_LOG_DIR; static int tty_log_fd = -1; #define TTY_LOG_OPEN 1 @@ -104,7 +104,7 @@ tty_log_fd = strtoul(name, &end, 0); if(*end != '\0'){ - printk("set_tty_log_dir - strtoul failed on '%s'\n", name); + printk("set_tty_log_fd - strtoul failed on '%s'\n", name); tty_log_fd = -1; } return 0; diff -Nru a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c --- a/arch/um/kernel/um_arch.c Tue Oct 15 20:29:20 2002 +++ b/arch/um/kernel/um_arch.c Tue Oct 15 20:29:20 2002 @@ -37,6 +37,11 @@ #define DEFAULT_COMMAND_LINE "root=6200" +struct cpuinfo_um boot_cpu_data = { + .loops_per_jiffy = 0, + .ipi_pipe = { -1, -1 } +}; + unsigned long thread_saved_pc(struct task_struct *task) { return(os_process_pc(task->thread.extern_pid)); @@ -119,6 +124,7 @@ #define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) #define START (TOP - SIZE) +/* Set in main */ unsigned long host_task_size; unsigned long task_size; @@ -129,17 +135,21 @@ task_size = START; } +/* Set in early boot */ unsigned long uml_physmem; unsigned long uml_reserved; - unsigned long start_vm; unsigned long end_vm; - int ncpus = 1; +/* Pointer set in linux_main, the array itself is private to each thread, + * and changed at address space creation time so this poses no concurrency + * problems. + */ static char *argv1_begin = NULL; static char *argv1_end = NULL; +/* Set in early boot */ static int have_root __initdata = 0; long physmem_size = 32 * 1024 * 1024; @@ -258,8 +268,9 @@ } extern int debug_trace; -unsigned long brk_start; +/* Set during early boot */ +unsigned long brk_start; static struct vm_reserved kernel_vm_reserved; #define MIN_VMALLOC (32 * 1024 * 1024) @@ -316,11 +327,12 @@ end_vm = start_vm + virtmem_size; if(virtmem_size < physmem_size) - printk(KERN_INFO "Kernel virtual memory size shrunk to %ld " - "bytes\n", virtmem_size); + printf("Kernel virtual memory size shrunk to %ld bytes\n", + virtmem_size); err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved); - if(err) panic("Failed to reserve VM area for kernel VM\n"); + if(err) + tracer_panic("Failed to reserve VM area for kernel VM\n"); uml_postsetup(); @@ -363,18 +375,6 @@ arch_check_bugs(); check_ptrace(); check_sigio(); -} - -spinlock_t pid_lock = SPIN_LOCK_UNLOCKED; - -void lock_pid(void) -{ - spin_lock(&pid_lock); -} - -void unlock_pid(void) -{ - spin_unlock(&pid_lock); } /* diff -Nru a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c --- a/arch/um/kernel/umid.c Tue Oct 15 20:29:21 2002 +++ b/arch/um/kernel/umid.c Tue Oct 15 20:29:21 2002 @@ -21,9 +21,13 @@ #define UMID_LEN 64 #define UML_DIR "~/.uml/" +/* Changed by set_umid and make_umid, which are run early in boot */ static char umid[UMID_LEN] = { 0 }; + +/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ static char *uml_dir = UML_DIR; +/* Changed by set_umid */ static int umid_is_random = 1; static int umid_inited = 0; diff -Nru a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c --- a/arch/um/kernel/user_util.c Tue Oct 15 20:29:12 2002 +++ b/arch/um/kernel/user_util.c Tue Oct 15 20:29:12 2002 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -32,6 +32,7 @@ #define COMMAND_LINE_SIZE _POSIX_ARG_MAX +/* Changed in linux_main and setup_arch, which run before SMP is started */ char saved_command_line[COMMAND_LINE_SIZE] = { 0 }; char command_line[COMMAND_LINE_SIZE] = { 0 }; @@ -182,85 +183,6 @@ uname(&host); sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename, host.release, host.version, host.machine); -} - -void close_fd(int fd) -{ - close(fd); -} - -char *tempdir = NULL; - -static void __init find_tempdir(void) -{ - char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; - int i; - char *dir = NULL; - - if(tempdir != NULL) return; /* We've already been called */ - for(i = 0; dirs[i]; i++){ - dir = getenv(dirs[i]); - if(dir != NULL) break; - } - if(dir == NULL) dir = "/tmp"; - else if(*dir == '\0') dir = NULL; - if(dir != NULL) { - tempdir = malloc(strlen(dir) + 2); - if(tempdir == NULL){ - fprintf(stderr, "Failed to malloc tempdir, " - "errno = %d\n", errno); - return; - } - strcpy(tempdir, dir); - strcat(tempdir, "/"); - } -} - -int make_tempfile(const char *template, char **out_tempname, int do_unlink) -{ - char tempname[MAXPATHLEN]; - int fd; - - find_tempdir(); - if (*template != '/') - strcpy(tempname, tempdir); - else - *tempname = 0; - strcat(tempname, template); - if((fd = mkstemp(tempname)) < 0){ - fprintf(stderr, "open - cannot create %s: %s\n", tempname, - strerror(errno)); - return -1; - } - if(do_unlink && (unlink(tempname) < 0)){ - perror("unlink"); - return -1; - } - if(out_tempname){ - if((*out_tempname = strdup(tempname)) == NULL){ - perror("strdup"); - return -1; - } - } - return(fd); -} - -int user_read(int fd, char *buf, int len) -{ - int err; - - err = read(fd, buf, len); - if(err < 0) return(-errno); - else return(err); -} - -int user_write(int fd, char *buf, int len) -{ - int err; - - err = write(fd, buf, len); - if(err < 0) return(-errno); - else return(err); } /* diff -Nru a/arch/um/main.c b/arch/um/main.c --- a/arch/um/main.c Tue Oct 15 20:29:14 2002 +++ b/arch/um/main.c Tue Oct 15 20:29:14 2002 @@ -18,15 +18,22 @@ #include "user.h" #include "init.h" +/* Set in set_stklim, which is called from main and __wrap_malloc. + * __wrap_malloc only calls it if main hasn't started. + */ unsigned long stacksizelim; +/* Set in main */ char *linux_prog; #define PGD_BOUND (4 * 1024 * 1024) #define STACKSIZE (8 * 1024 * 1024) #define THREAD_NAME_LEN (256) -char padding[THREAD_NAME_LEN] = { [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0' }; +/* Never changed */ +static char padding[THREAD_NAME_LEN] = { + [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0' +}; static void set_stklim(void) { @@ -129,7 +136,8 @@ return(uml_exitcode); } -int allocating_monbuf = 0; +/* Changed in __wrap___monstartup and __wrap_malloc very early */ +static int allocating_monbuf = 0; #ifdef PROFILING extern void __real___monstartup (unsigned long, unsigned long); @@ -146,6 +154,7 @@ extern void *__real_malloc(int); extern unsigned long host_task_size; +/* Set in __wrap_malloc early */ static void *gmon_buf = NULL; void *__wrap_malloc(int size) diff -Nru a/arch/um/ptproxy/proxy.c b/arch/um/ptproxy/proxy.c --- a/arch/um/ptproxy/proxy.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/ptproxy/proxy.c Tue Oct 15 20:29:17 2002 @@ -30,6 +30,7 @@ #include "user_util.h" #include "user.h" #include "os.h" +#include "tempfile.h" static int debugger_wait(debugger_state *debugger, int *status, int options, int (*syscall)(debugger_state *debugger, pid_t child), @@ -122,6 +123,7 @@ return(0); } +/* Used by the tracing thread */ static debugger_state parent; static int parent_syscall(debugger_state *debugger, int pid); @@ -174,10 +176,7 @@ syscall_continue(debugger->pid); } -#ifdef CONFIG_SMP -#error need to make these arrays -#endif - +/* Used by the tracing thread */ static debugger_state debugger; static debugee_state debugee; diff -Nru a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c --- a/arch/um/sys-i386/bugs.c Tue Oct 15 20:29:20 2002 +++ b/arch/um/sys-i386/bugs.c Tue Oct 15 20:29:20 2002 @@ -15,6 +15,7 @@ #define MAXTOKEN 64 +/* Set during early boot */ int cpu_has_cmov = 1; int cpu_has_xmm = 0; diff -Nru a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c --- a/arch/um/sys-i386/ptrace_user.c Tue Oct 15 20:29:14 2002 +++ b/arch/um/sys-i386/ptrace_user.c Tue Oct 15 20:29:14 2002 @@ -59,6 +59,7 @@ } } +/* Accessed only by the tracing thread */ static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; static int debugregs_seq = 0; diff -Nru a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile --- a/arch/um/sys-i386/util/Makefile Tue Oct 15 20:29:16 2002 +++ b/arch/um/sys-i386/util/Makefile Tue Oct 15 20:29:16 2002 @@ -1,16 +1,18 @@ -host-progs = mk_sc +EXTRA_TARGETS := mk_sc mk_thread mk_thread_kern.o -mk_sc-objs = mk_sc.o +host-progs := mk_sc + +mk_sc-objs := mk_sc.o include $(TOPDIR)/Rules.make -mk_thread : mk_thread_kern.o mk_thread_user.o - $(CC) $(CFLAGS) -o $@ mk_thread_user.o mk_thread_kern.o +$(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o + $(CC) $(CFLAGS) -o $@ $^ -mk_thread_user.o : mk_thread_user.c +$(obj)/mk_thread_user.o : $(src)/mk_thread_user.c $(CC) $(USER_CFLAGS) -c -o $@ $< clean : - $(RM) $(host-progs) mk_thread + $(RM) -f $(EXTRA_TARGETS) archmrproper : clean diff -Nru a/arch/um/sys-ppc/miscthings.c b/arch/um/sys-ppc/miscthings.c --- a/arch/um/sys-ppc/miscthings.c Tue Oct 15 20:29:17 2002 +++ b/arch/um/sys-ppc/miscthings.c Tue Oct 15 20:29:17 2002 @@ -2,9 +2,6 @@ #include "linux/stddef.h" // for NULL #include "linux/elf.h" // for AT_NULL -/* unsigned int local_bh_count[NR_CPUS]; */ -unsigned long isa_io_base = 0; - /* The following function nicked from arch/ppc/kernel/process.c and * adapted slightly */ /* diff -Nru a/arch/um/uml.lds.S b/arch/um/uml.lds.S --- a/arch/um/uml.lds.S Tue Oct 15 20:29:16 2002 +++ b/arch/um/uml.lds.S Tue Oct 15 20:29:16 2002 @@ -67,6 +67,9 @@ __setup_start = .; .setup.init : { *(.setup.init) } __setup_end = .; + __per_cpu_start = . ; + .data.percpu : { *(.data.percpu) } + __per_cpu_end = . ; __initcall_start = .; .initcall.init : { *(.initcall1.init) diff -Nru a/arch/um/util/Makefile b/arch/um/util/Makefile --- a/arch/um/util/Makefile Tue Oct 15 20:29:23 2002 +++ b/arch/um/util/Makefile Tue Oct 15 20:29:23 2002 @@ -1,14 +1,14 @@ -include $(TOPDIR)/Rules.make +EXTRA_TARGETS := mk_task mk_task_kern.o -all : mk_task +include $(TOPDIR)/Rules.make -mk_task : mk_task_user.o mk_task_kern.o - $(CC) -o mk_task mk_task_user.o mk_task_kern.o +$(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o + $(CC) -o $@ $^ -mk_task_user.o : mk_task_user.c - $(CC) -c $< +$(obj)/mk_task_user.o: $(src)/mk_task_user.c + $(CC) -o $@ -c $< -clean : - $(RM) mk_task *.o *~ +clean: + $(RM) $(EXTRA_TARGETS) -archmrproper : clean +archmrproper: diff -Nru a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile --- a/arch/x86_64/boot/Makefile Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/boot/Makefile Tue Oct 15 20:29:16 2002 @@ -21,28 +21,52 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA -# --------------------------------------------------------------------------- +# If you want the RAM disk device, define this to be the size in blocks. + +#RAMDISK := -DRAMDISK=512 + +EXTRA_TARGETS := vmlinux.bin bootsect bootsect.o \ + setup setup.o zImage bzImage -BOOT_INCL = $(TOPDIR)/include/linux/config.h \ - $(TOPDIR)/include/linux/autoconf.h \ - $(TOPDIR)/include/asm/boot.h - -zImage: bootsect setup compressed/vmlinux tools/build - $(OBJCOPY) $(OBJCOPYFLAGS) compressed/vmlinux compressed/vmlinux.out - tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage - -bzImage: bbootsect bsetup compressed/bvmlinux tools/build - $(OBJCOPY) $(OBJCOPYFLAGS) compressed/bvmlinux compressed/bvmlinux.out - tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage +CFLAGS += -m32 -bzImage-padded: bzImage - dd if=/dev/zero bs=1k count=70 >> bzImage +host-progs := tools/build -compressed/vmlinux: $(TOPDIR)/vmlinux - @$(MAKE) -C compressed vmlinux +# Default + +boot: bzImage + +include $(TOPDIR)/Rules.make + +# --------------------------------------------------------------------------- + +$(obj)/zImage: IMAGE_OFFSET := 0x1000 +$(obj)/zImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) +$(obj)/bzImage: IMAGE_OFFSET := 0x100000 +$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ +$(obj)/bzImage: BUILDFLAGS := -b + +quiet_cmd_image = BUILD $(echo_target) +cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ + $(obj)/vmlinux.bin $(ROOT_DEV) > $@ + +$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ + $(obj)/vmlinux.bin $(obj)/tools/build FORCE + $(call if_changed,image) + +$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + +LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary +LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext + +$(obj)/setup $(obj)/bootsect: %: %.o FORCE + $(call if_changed,ld) + +$(obj)/compressed/vmlinux: FORCE + +@$(call descend,$(obj)/compressed,IMAGE_OFFSET=$(IMAGE_OFFSET) \ + $(obj)/compressed/vmlinux) -compressed/bvmlinux: $(TOPDIR)/vmlinux - @$(MAKE) -C compressed bvmlinux zdisk: $(BOOTIMAGE) dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0 @@ -51,53 +75,21 @@ if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz - cp $(TOPDIR)/System.map $(INSTALL_PATH)/ + cp System.map $(INSTALL_PATH)/ if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi install: $(BOOTIMAGE) - sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)" - -tools/build: tools/build.c - $(HOSTCC) $(HOSTCFLAGS) -o $@ $< - -bootsect: bootsect.o - $(IA32_LD) -Ttext 0x0 -s --oformat binary -o $@ $< - -bootsect.o: bootsect.s - $(IA32_AS) -o $@ $< - -bootsect.s: bootsect.S Makefile $(BOOT_INCL) - $(IA32_CPP) $(CPPFLAGS) -traditional -D__ASSEMBLY__ $(SVGA_MODE) $(RAMDISK) $< -o $@ - -bbootsect: bbootsect.o - $(IA32_LD) -Ttext 0x0 -s --oformat binary $< -o $@ - -bbootsect.o: bbootsect.s - $(IA32_AS) -o $@ $< - -bbootsect.s: bootsect.S Makefile $(BOOT_INCL) - $(IA32_CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ - -setup: setup.o - $(IA32_LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< - -setup.o: setup.s - $(IA32_AS) -o $@ $< - -setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(IA32_CPP) $(CPPFLAGS) -traditional -D__ASSEMBLY__ $(SVGA_MODE) $(RAMDISK) $< -o $@ - -bsetup: bsetup.o - $(IA32_LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< - -bsetup.o: bsetup.s - $(IA32_AS) -o $@ $< - -bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(IA32_CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + sh $(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" clean: - rm -f tools/build - rm -f setup bootsect zImage compressed/vmlinux.out - rm -f bsetup bbootsect bzImage compressed/bvmlinux.out - @$(MAKE) -C compressed clean + @echo 'Cleaning up (boot)' + @rm -f $(host-progs) $(EXTRA_TARGETS) + +@$(call descend,$(obj)/compressed) clean + +archhelp: + @echo '* bzImage - Compressed kernel image (arch/$(ARCH)/boot/bzImage)' + @echo ' install - Install kernel using' + @echo ' (your) ~/bin/installkernel or' + @echo ' (distribution) /sbin/installkernel or' + @echo ' install to $$(INSTALL_PATH) and run lilo' + diff -Nru a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile --- a/arch/x86_64/boot/compressed/Makefile Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/boot/compressed/Makefile Tue Oct 15 20:29:16 2002 @@ -1,43 +1,38 @@ # -# linux/arch/i386/boot/compressed/Makefile +# linux/arch/x86_64/boot/compressed/Makefile # # create a compressed vmlinux image from the original vmlinux # +# Note all the files here are compiled/linked as 32bit executables. +# -HEAD = head.o -SYSTEM = $(TOPDIR)/vmlinux - -OBJECTS = $(HEAD) misc.o +EXTRA_TARGETS := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o +EXTRA_AFLAGS := -traditional -m32 -IA32_CFLAGS := -O2 -DSTDC_HEADERS +# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with +# -m32 +CFLAGS := -m32 -D__KERNEL__ -I$(TOPDIR)/include -O2 +LDFLAGS := -m elf_i386 -# -# ZIMAGE_OFFSET is the load offset of the compression loader -# BZIMAGE_OFFSET is the load offset of the high loaded compression loader -# -BZIMAGE_OFFSET = 0x100000 +include $(TOPDIR)/Rules.make -BZLINKFLAGS = -Ttext $(BZIMAGE_OFFSET) $(ZLDFLAGS) +LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386 -all: vmlinux +$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE + $(call if_changed,ld) -bvmlinux: piggy.o $(OBJECTS) - $(IA32_LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o +$(obj)/vmlinux.bin: vmlinux FORCE + strip vmlinux + $(call if_changed,objcopy) -head.o: head.S - $(IA32_AS) -c head.S +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) -misc.o: misc.c - $(IA32_CC) $(IA32_CFLAGS) -c misc.c +LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T -piggy.o: $(SYSTEM) - tmppiggy=_tmp_$$$$piggy; \ - rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ - $(OBJCOPY) $(OBJCOPYFLAGS) $< $$tmppiggy; \ - gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ - echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ - $(IA32_LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \ - rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) clean: - rm -f vmlinux bvmlinux _tmp_* + @echo 'Cleaning up (boot/compressed)' + @rm -f $(EXTRA_TARGETS) diff -Nru a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c --- a/arch/x86_64/boot/compressed/misc.c Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/boot/compressed/misc.c Tue Oct 15 20:29:16 2002 @@ -89,12 +89,8 @@ static uch *output_data; static unsigned long output_ptr = 0; - static void *malloc(int size); static void free(void *where); -static void error(char *m); -static void gzip_mark(void **); -static void gzip_release(void **); static void puts(const char *); diff -Nru a/arch/x86_64/boot/compressed/miscsetup.h b/arch/x86_64/boot/compressed/miscsetup.h --- a/arch/x86_64/boot/compressed/miscsetup.h Tue Oct 15 20:29:21 2002 +++ b/arch/x86_64/boot/compressed/miscsetup.h Tue Oct 15 20:29:21 2002 @@ -1,5 +1,5 @@ #define NULL 0 -typedef unsigned int size_t; +//typedef unsigned int size_t; struct screen_info { diff -Nru a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux.scr --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/boot/compressed/vmlinux.scr Tue Oct 15 20:29:25 2002 @@ -0,0 +1,9 @@ +SECTIONS +{ + .data : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; + *(.data) + input_data_end = .; + } +} diff -Nru a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S --- a/arch/x86_64/boot/video.S Tue Oct 15 20:29:17 2002 +++ b/arch/x86_64/boot/video.S Tue Oct 15 20:29:17 2002 @@ -95,6 +95,7 @@ #define PARAM_VESAPM_SEG 0x2e #define PARAM_VESAPM_OFF 0x30 #define PARAM_LFB_PAGES 0x32 +#define PARAM_VESA_ATTRIB 0x34 /* Define DO_STORE according to CONFIG_VIDEO_RETAIN */ @@ -220,6 +221,8 @@ movl %eax, %fs:(PARAM_LFB_COLORS) movl 35(%di), %eax movl %eax, %fs:(PARAM_LFB_COLORS+4) + movw 0(%di), %ax + movw %ax, %fs:(PARAM_VESA_ATTRIB) # get video mem size leaw modelist+1024, %di diff -Nru a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile --- a/arch/x86_64/ia32/Makefile Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/ia32/Makefile Tue Oct 15 20:29:15 2002 @@ -2,17 +2,10 @@ # Makefile for the ia32 kernel emulation subsystem. # -USE_STANDARD_AS_RULE := true - export-objs := ia32_ioctl.o sys_ia32.o -all: ia32.o - -O_TARGET := ia32.o obj-$(CONFIG_IA32_EMULATION) := ia32entry.o sys_ia32.o ia32_ioctl.o \ ia32_signal.o \ ia32_binfmt.o fpu32.o socket32.o ptrace32.o ipc32.o - -clean:: include $(TOPDIR)/Rules.make diff -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c --- a/arch/x86_64/ia32/ia32_binfmt.c Tue Oct 15 20:29:11 2002 +++ b/arch/x86_64/ia32/ia32_binfmt.c Tue Oct 15 20:29:11 2002 @@ -58,6 +58,8 @@ int tv_sec, tv_usec; }; +#define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0) + struct elf_prstatus { struct elf_siginfo pr_info; /* Info associated with signal */ @@ -162,6 +164,7 @@ #define ELF_PLAT_INIT(r) elf32_init(r) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) +int ia32_setup_arg_pages(struct linux_binprm *bprm); #undef start_thread #define start_thread(regs,new_rip,new_rsp) do { \ diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c --- a/arch/x86_64/ia32/ia32_ioctl.c Tue Oct 15 20:29:17 2002 +++ b/arch/x86_64/ia32/ia32_ioctl.c Tue Oct 15 20:29:17 2002 @@ -55,6 +55,7 @@ #include #include #include +#include #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) /* Ugh. This header really is not clean */ #define min min @@ -2000,6 +2001,7 @@ #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) /* Ugh, LVM. Pitty it was not cleaned up before accepted :((. */ +/* AK: dev_t/kdev_t use here is somewhat dubious */ typedef struct { uint8_t vg_name[NAME_LEN]; uint32_t vg_number; @@ -2034,7 +2036,7 @@ uint8_t pv_name[NAME_LEN]; uint8_t vg_name[NAME_LEN]; uint8_t system_id[NAME_LEN]; - kdev_t pv_dev; + __u32 pv_dev; uint32_t pv_number; uint32_t pv_status; uint32_t pv_allocatable; @@ -3084,38 +3086,108 @@ return err; } -static int generic_long_put(unsigned int fd, unsigned int cmd, unsigned long arg) + +struct dirent32 { + unsigned int d_ino; + __kernel_off_t32 d_off; + unsigned short d_reclen; + char d_name[256]; /* We must not include limits.h! */ +}; + +#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct dirent32 [2]) +#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct dirent32 [2]) + +static int put_dirent32(struct dirent *src, struct dirent32 *dst) { int ret; - unsigned long val = 0; - mm_segment_t oldseg = get_fs(); + ret = put_user(src->d_ino, &dst->d_ino); + ret |= __put_user(src->d_off, &dst->d_off); + ret |= __put_user(src->d_reclen, &dst->d_reclen); + if (__copy_to_user(&dst->d_name, src->d_name, src->d_reclen)) + ret |= -EFAULT; + return ret; +} + +static int vfat_ioctl32(unsigned fd, unsigned cmd, void *ptr) +{ + int ret; + mm_segment_t oldfs = get_fs(); + struct dirent d[2]; + set_fs(KERNEL_DS); - cmd = (cmd & 0xc000ffff) | (sizeof(unsigned long) << _IOC_SIZESHIFT); - ret = sys_ioctl(fd, cmd, (unsigned long)&val); - set_fs(oldseg); - if (!ret || val) { - if (put_user((int)val, (unsigned int *)arg)) - return -EFAULT; + ret = sys_ioctl(fd,cmd,(unsigned long)&d); + set_fs(oldfs); + if (!ret) { + ret |= put_dirent32(&d[0], (struct dirent32 *)ptr); + ret |= put_dirent32(&d[1], ((struct dirent32 *)ptr) + 1); } return ret; } -static int generic_long_get(unsigned int fd, unsigned int cmd, unsigned long arg) + + +#define REISERFS_IOC_UNPACK32 _IOW(0xCD,1,int) + +static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) +{ + if (cmd == REISERFS_IOC_UNPACK32) + cmd = REISERFS_IOC_UNPACK; + return sys_ioctl(fd,cmd,ptr); +} + +#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) + +static int autofs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr) { int ret; - unsigned int ival; - unsigned long val = 0; - mm_segment_t oldseg = get_fs(); - if (get_user(ival, (unsigned int *)arg)) - return -EFAULT; - val = ival; + unsigned long val; + mm_segment_t oldfs = get_fs(); set_fs(KERNEL_DS); - cmd = (cmd & 0xc000ffff) | (sizeof(unsigned long) << _IOC_SIZESHIFT); - ret = sys_ioctl(fd, cmd, (unsigned long)&val); - set_fs(oldseg); + ret = sys_ioctl(fd, AUTOFS_IOC_SETTIMEOUT32, (unsigned long)&val); + set_fs(oldfs); + if (!ret) + ret = put_user(val, (int *) ptr); return ret; } +#define RTC_IRQP_READ32 _IOR('p', 0x0b, unsigned int) /* Read IRQ rate */ +#define RTC_IRQP_SET32 _IOW('p', 0x0c, unsigned int) /* Set IRQ rate */ +#define RTC_EPOCH_READ32 _IOR('p', 0x0d, unsigned) /* Read epoch */ +#define RTC_EPOCH_SET32 _IOW('p', 0x0e, unsigned) /* Set epoch */ + +static int rtc32_ioctl(unsigned fd, unsigned cmd, unsigned long arg) +{ + unsigned long val; + mm_segment_t oldfs = get_fs(); + int ret; + + switch (cmd) { + case RTC_IRQP_READ32: + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, RTC_IRQP_READ, (unsigned long)&val); + set_fs(oldfs); + if (!ret) + ret = put_user(val, (unsigned int*) arg); + return ret; + + case RTC_IRQP_SET32: + cmd = RTC_EPOCH_SET; + break; + + case RTC_EPOCH_READ32: + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, RTC_EPOCH_READ, (unsigned long) &val); + set_fs(oldfs); + if (!ret) + ret = put_user(val, (unsigned int*) arg); + return ret; + + case RTC_EPOCH_SET32: + cmd = RTC_EPOCH_SET; + break; + } + return sys_ioctl(fd,cmd,arg); +} struct ioctl_trans { unsigned long cmd; @@ -3344,14 +3416,10 @@ COMPATIBLE_IOCTL(RTC_SET_TIME) COMPATIBLE_IOCTL(RTC_WKALM_SET) COMPATIBLE_IOCTL(RTC_WKALM_RD) -#define RTC_IRQP_READ32 _IOR('p', 0x0b, unsigned int) /* Read IRQ rate */ -HANDLE_IOCTL(RTC_IRQP_READ32,generic_long_put) -#define RTC_IRQP_SET32 _IOW('p', 0x0c, unsigned int) /* Set IRQ rate */ -HANDLE_IOCTL(RTC_IRQP_SET32,generic_long_get) -#define RTC_EPOCH_READ32 _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET32 _IOW('p', 0x0e, unsigned long) /* Set epoch */ -HANDLE_IOCTL(RTC_EPOCH_READ32, generic_long_put) -HANDLE_IOCTL(RTC_EPOCH_SET32, generic_long_get) +HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl) +HANDLE_IOCTL(RTC_IRQP_SET32,rtc32_ioctl) +HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl) +HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl) /* Little m */ COMPATIBLE_IOCTL(MTIOCTOP) /* Socket level stuff */ @@ -3619,8 +3687,7 @@ COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC) COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) -#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) -HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, generic_long_get); +HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, autofs_ioctl32); /* DEVFS */ COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV) COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK) @@ -3687,7 +3754,9 @@ COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK) COMPATIBLE_IOCTL(DRM_IOCTL_FINISH) #endif /* DRM */ -COMPATIBLE_IOCTL(REISERFS_IOC_UNPACK); +HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32); +HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32); +HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32); /* serial driver */ HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl); HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl); @@ -3854,6 +3923,8 @@ #define IOCTL_HASHSIZE 256 struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE]; +extern struct ioctl_trans ioctl_start[], ioctl_end[]; + static inline unsigned long ioctl32_hash(unsigned long cmd) { return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE; @@ -3879,7 +3950,6 @@ static int __init init_sys32_ioctl(void) { int i; - extern struct ioctl_trans ioctl_start[], ioctl_end[]; for (i = 0; &ioctl_start[i] < &ioctl_end[0]; i++) { if (ioctl_start[i].next != 0) { @@ -3894,57 +3964,108 @@ __initcall(init_sys32_ioctl); -static struct ioctl_trans *additional_ioctls; - -/* Always call these with kernel lock held! */ +static struct ioctl_trans *ioctl_free_list; +/* Never free them really. This avoids SMP races. With a Read-Copy-Update + enabled kernel we could just use the RCU infrastructure for this. */ +static void free_ioctl(struct ioctl_trans *t) +{ + t->cmd = 0; + mb(); + t->next = ioctl_free_list; + ioctl_free_list = t; +} int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)) { - int i; - if (!additional_ioctls) { - additional_ioctls = (struct ioctl_trans *)get_zeroed_page(GFP_KERNEL); - if (!additional_ioctls) - return -ENOMEM; + struct ioctl_trans *t; + unsigned long hash = ioctl32_hash(cmd); + + lock_kernel(); + for (t = (struct ioctl_trans *)ioctl32_hash_table[hash]; + t; + t = t->next) { + if (t->cmd == cmd) { + printk("Trying to register duplicated ioctl32 handler %x\n", cmd); + unlock_kernel(); + return -EINVAL; } - for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++) - if (!additional_ioctls[i].cmd) - break; - if (i == PAGE_SIZE/sizeof(struct ioctl_trans)) + } + + if (ioctl_free_list) { + t = ioctl_free_list; + ioctl_free_list = t->next; + } else { + t = kmalloc(sizeof(struct ioctl_trans), GFP_KERNEL); + if (!t) { + unlock_kernel(); return -ENOMEM; - additional_ioctls[i].cmd = cmd; - if (!handler) - additional_ioctls[i].handler = - (int (*)(unsigned,unsigned,unsigned long, struct file *))sys_ioctl; - else - additional_ioctls[i].handler = handler; - ioctl32_insert_translation(&additional_ioctls[i]); + } + } + + t->next = NULL; + t->cmd = cmd; + t->handler = handler; + ioctl32_insert_translation(t); + + unlock_kernel(); return 0; } +static inline int builtin_ioctl(struct ioctl_trans *t) +{ + return t >= (struct ioctl_trans *)ioctl_start && + t < (struct ioctl_trans *)ioctl_end; +} + +/* Problem: + This function cannot unregister duplicate ioctls, because they are not + unique. + When they happen we need to extend the prototype to pass handler too. */ int unregister_ioctl32_conversion(unsigned int cmd) { unsigned long hash = ioctl32_hash(cmd); struct ioctl_trans *t, *t1; - t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash]; - if (!t) return -EINVAL; - if (t->cmd == cmd && t >= additional_ioctls && - (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) { + lock_kernel(); + + t = (struct ioctl_trans *)ioctl32_hash_table[hash]; + if (!t) { + unlock_kernel(); + return -EINVAL; + } + + if (t->cmd == cmd) { + if (builtin_ioctl(t)) { + printk("%p tried to unregister builtin ioctl %x\n", + __builtin_return_address(0), cmd); + } else { ioctl32_hash_table[hash] = t->next; - t->cmd = 0; + free_ioctl(t); + unlock_kernel(); return 0; - } else while (t->next) { + } + } + while (t->next) { t1 = (struct ioctl_trans *)(long)t->next; - if (t1->cmd == cmd && t1 >= additional_ioctls && - (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) { - t1->cmd = 0; + if (t1->cmd == cmd) { + if (builtin_ioctl(t1)) { + printk("%p tried to unregister builtin ioctl %x\n", + __builtin_return_address(0), cmd); + goto out; + } else { t->next = t1->next; + free_ioctl(t1); + unlock_kernel(); return 0; } + } t = t1; } + printk(KERN_ERR "Trying to free unknown 32bit ioctl handler %x\n", cmd); + out: + unlock_kernel(); return -EINVAL; } @@ -3967,10 +4088,10 @@ goto out; } - t = (struct ioctl_trans *)(long)ioctl32_hash_table [ioctl32_hash (cmd)]; + t = (struct ioctl_trans *)ioctl32_hash_table [ioctl32_hash (cmd)]; while (t && t->cmd != cmd) - t = (struct ioctl_trans *)(long)t->next; + t = (struct ioctl_trans *)t->next; if (t) { handler = t->handler; error = handler(fd, cmd, arg, filp); diff -Nru a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c --- a/arch/x86_64/ia32/ia32_signal.c Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/ia32/ia32_signal.c Tue Oct 15 20:29:16 2002 @@ -81,11 +81,11 @@ sigset_t saveset; mask &= _BLOCKABLE; - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); regs.rax = -EINTR; while (1) { @@ -170,10 +170,7 @@ asm volatile("movl %%" #seg ",%0" : "=r" (cur)); \ if (pre != cur) loadsegment(seg,pre); } - /* Reload fs and gs if they have changed in the signal handler. - This does not handle long fs/gs base changes in the handler, but does not clobber - them at least in the normal case. */ - + /* Reload fs and gs if they have changed in the signal handler. */ { unsigned short gs; @@ -181,11 +178,18 @@ load_gs_index(gs); } RELOAD_SEG(fs); + RELOAD_SEG(ds); + RELOAD_SEG(es); COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx); COPY(dx); COPY(cx); COPY(ip); /* Don't touch extended registers */ + err |= __get_user(regs->cs, &sc->cs); + regs->cs |= 2; + err |= __get_user(regs->ss, &sc->ss); + regs->ss |= 2; + { unsigned int tmpflags; err |= __get_user(tmpflags, &sc->eflags); @@ -231,10 +235,10 @@ goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); if (ia32_restore_sigcontext(®s, &frame->sc, &eax)) goto badframe; @@ -258,10 +262,10 @@ goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); if (ia32_restore_sigcontext(®s, &frame->uc.uc_mcontext, &eax)) goto badframe; @@ -299,6 +303,10 @@ err |= __put_user(tmp, (unsigned int *)&sc->gs); __asm__("movl %%fs,%0" : "=r"(tmp): "0"(tmp)); err |= __put_user(tmp, (unsigned int *)&sc->fs); + __asm__("movl %%ds,%0" : "=r"(tmp): "0"(tmp)); + err |= __put_user(tmp, (unsigned int *)&sc->ds); + __asm__("movl %%es,%0" : "=r"(tmp): "0"(tmp)); + err |= __put_user(tmp, (unsigned int *)&sc->es); err |= __put_user((u32)regs->rdi, &sc->edi); err |= __put_user((u32)regs->rsi, &sc->esi); @@ -308,6 +316,8 @@ err |= __put_user((u32)regs->rdx, &sc->edx); err |= __put_user((u32)regs->rcx, &sc->ecx); err |= __put_user((u32)regs->rax, &sc->eax); + err |= __put_user((u32)regs->cs, &sc->cs); + err |= __put_user((u32)regs->ss, &sc->ss); err |= __put_user(current->thread.trap_no, &sc->trapno); err |= __put_user(current->thread.error_code, &sc->err); err |= __put_user((u32)regs->rip, &sc->eip); @@ -406,8 +416,13 @@ regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); + asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); + + regs->cs = __USER32_CS; + regs->ss = __USER32_DS; + set_fs(USER_DS); - // XXX: cs regs->eflags &= ~TF_MASK; #if DEBUG_SIG @@ -479,8 +494,13 @@ regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + asm volatile("movl %0,%%ds" :: "r" (__USER32_DS)); + asm volatile("movl %0,%%es" :: "r" (__USER32_DS)); + + regs->cs = __USER32_CS; + regs->ss = __USER32_DS; + set_fs(USER_DS); - // XXX: cs regs->eflags &= ~TF_MASK; #if DEBUG_SIG diff -Nru a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S --- a/arch/x86_64/ia32/ia32entry.S Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/ia32/ia32entry.S Tue Oct 15 20:29:16 2002 @@ -171,7 +171,7 @@ .quad sys_umount /* new_umount */ .quad ni_syscall /* old lock syscall holder */ .quad sys32_ioctl - .quad sys32_fcntl /* 55 */ + .quad sys32_fcntl64 /* 55 */ .quad ni_syscall /* old mpx syscall holder */ .quad sys_setpgid .quad ni_syscall /* old ulimit syscall holder */ @@ -319,15 +319,15 @@ .quad sys_getgid /* 200 */ .quad sys_geteuid .quad sys_getegid - .quad sys32_setreuid - .quad sys32_setregid - .quad sys32_getgroups /* 205 */ - .quad sys32_setgroups + .quad sys_setreuid + .quad sys_setregid + .quad sys_getgroups /* 205 */ + .quad sys_setgroups .quad sys_fchown - .quad sys32_setresuid - .quad sys32_getresuid - .quad sys32_setresgid /* 210 */ - .quad sys32_getresgid + .quad sys_setresuid + .quad sys_getresuid + .quad sys_setresgid /* 210 */ + .quad sys_getresgid .quad sys_chown .quad sys_setuid .quad sys_setgid @@ -356,9 +356,19 @@ .quad sys_fremovexattr .quad sys_tkill /* 238 */ .quad sys_sendfile64 - .quad sys_futex + .quad sys_futex /* 240 */ .quad sys32_sched_setaffinity .quad sys32_sched_getaffinity + .quad sys_set_thread_area + .quad sys_get_thread_area + .quad sys32_io_setup + .quad sys_io_destroy + .quad sys_io_getevents + .quad sys_io_submit + .quad sys_io_cancel + .quad sys_ni_syscall /* 250 alloc_huge_pages */ + .quad sys_ni_syscall /* free_huge_pages */ + .quad sys_ni_syscall /* exit_group */ ia32_syscall_end: .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8 .quad ni_syscall diff -Nru a/arch/x86_64/ia32/ipc32.c b/arch/x86_64/ia32/ipc32.c --- a/arch/x86_64/ia32/ipc32.c Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/ia32/ipc32.c Tue Oct 15 20:29:16 2002 @@ -152,8 +152,8 @@ }; struct ipc_kludge { - struct msgbuf *msgp; - int msgtyp; + u32 msgp; + s32 msgtyp; }; @@ -268,14 +268,19 @@ return err; } +#define MAXBUF (64*1024) + static int do_sys32_msgsnd (int first, int second, int third, void *uptr) { - struct msgbuf *p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); + struct msgbuf *p; struct msgbuf32 *up = (struct msgbuf32 *)uptr; mm_segment_t old_fs; int err; + if (second >= MAXBUF-sizeof(struct msgbuf)) + return -EINVAL; + p = kmalloc(second + sizeof(struct msgbuf), GFP_USER); if (!p) return -ENOMEM; err = get_user(p->mtype, &up->mtype); @@ -312,13 +317,15 @@ uptr = (void *)A(ipck.msgp); msgtyp = ipck.msgtyp; } + if (second >= MAXBUF-sizeof(struct msgbuf)) + return -EINVAL; err = -ENOMEM; - p = kmalloc(second + sizeof(struct msgbuf) + 4, GFP_USER); + p = kmalloc(second + sizeof(struct msgbuf), GFP_USER); if (!p) goto out; old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_msgrcv(first, p, second + 4, msgtyp, third); + err = sys_msgrcv(first, p, second, msgtyp, third); set_fs(old_fs); if (err < 0) goto free_then_out; diff -Nru a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c --- a/arch/x86_64/ia32/ptrace32.c Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/ia32/ptrace32.c Tue Oct 15 20:29:15 2002 @@ -24,6 +24,7 @@ #include #include #include +#include #define R32(l,q) \ case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break @@ -35,20 +36,32 @@ switch (regno) { case offsetof(struct user32, regs.fs): + if (val && (val & 3) != 3) return -EIO; child->thread.fs = val; break; case offsetof(struct user32, regs.gs): + if (val && (val & 3) != 3) return -EIO; child->thread.gs = val; break; case offsetof(struct user32, regs.ds): + if (val && (val & 3) != 3) return -EIO; child->thread.ds = val; break; case offsetof(struct user32, regs.es): + if (val && (val & 3) != 3) return -EIO; child->thread.es = val; break; - R32(cs, cs); - R32(ss, ss); + case offsetof(struct user32, regs.ss): + if ((val & 3) != 3) return -EIO; + stack[offsetof(struct pt_regs, ss)/8] = val; + break; + + case offsetof(struct user32, regs.cs): + if ((val & 3) != 3) return -EIO; + stack[offsetof(struct pt_regs, cs)/8] = val; + break; + R32(ebx, rbx); R32(ecx, rcx); R32(edx, rdx); diff -Nru a/arch/x86_64/ia32/socket32.c b/arch/x86_64/ia32/socket32.c --- a/arch/x86_64/ia32/socket32.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/ia32/socket32.c Tue Oct 15 20:29:12 2002 @@ -436,20 +436,33 @@ sock = sockfd_lookup(fd, &err); if (sock != NULL) { - struct scm_cookie scm; + struct sock_iocb *si; + struct kiocb iocb; if (sock->file->f_flags & O_NONBLOCK) user_flags |= MSG_DONTWAIT; - memset(&scm, 0, sizeof(scm)); - err = sock->ops->recvmsg(sock, &kern_msg, total_len, - user_flags, &scm); + + init_sync_kiocb(&iocb, NULL); + si = kiocb_to_siocb(&iocb); + si->sock = sock; + si->scm = &si->async_scm; + si->msg = &kern_msg; + si->size = total_len; + si->flags = user_flags; + memset(si->scm, 0, sizeof(*si->scm)); + + err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len, + user_flags, si->scm); + if (-EIOCBQUEUED == err) + err = wait_on_sync_kiocb(&iocb); + if(err >= 0) { len = err; if(!kern_msg.msg_control) { - if(sock->passcred || scm.fp) + if(sock->passcred || si->scm->fp) kern_msg.msg_flags |= MSG_CTRUNC; - if(scm.fp) - __scm_destroy(&scm); + if(si->scm->fp) + __scm_destroy(si->scm); } else { /* If recvmsg processing itself placed some * control messages into user space, it's is @@ -463,9 +476,10 @@ if(sock->passcred) put_cmsg32(&kern_msg, SOL_SOCKET, SCM_CREDENTIALS, - sizeof(scm.creds), &scm.creds); - if(scm.fp != NULL) - scm_detach_fds32(&kern_msg, &scm); + sizeof(si->scm->creds), + &si->scm->creds); + if(si->scm->fp != NULL) + scm_detach_fds32(&kern_msg, si->scm); } } sockfd_put(sock); diff -Nru a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c --- a/arch/x86_64/ia32/sys_ia32.c Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/ia32/sys_ia32.c Tue Oct 15 20:29:16 2002 @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -1288,37 +1289,71 @@ extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); -asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +static inline int get_flock64(struct ia32_flock64 *fl32, struct flock *fl64) { - switch (cmd) { - case F_GETLK: - case F_SETLK: - case F_SETLKW: - { - struct flock f; - mm_segment_t old_fs; - long ret; - - if (get_flock(&f, (struct flock32 *)arg)) - return -EFAULT; - old_fs = get_fs(); set_fs (KERNEL_DS); - ret = sys_fcntl(fd, cmd, (unsigned long)&f); - set_fs (old_fs); - if (ret) return ret; - if (put_flock(&f, (struct flock32 *)arg)) - return -EFAULT; - return 0; + if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) { + int ret = __get_user(fl64->l_type, &fl32->l_type); + ret |= __get_user(fl64->l_whence, &fl32->l_whence); + ret |= __get_user(fl64->l_start, &fl32->l_start); + ret |= __get_user(fl64->l_len, &fl32->l_len); + ret |= __get_user(fl64->l_pid, &fl32->l_pid); + return ret; } - default: - return sys_fcntl(fd, cmd, (unsigned long)arg); + return -EFAULT; +} + +static inline int put_flock64(struct ia32_flock64 *fl32, struct flock *fl64) +{ + if (access_ok(fl32, sizeof(struct ia32_flock64), VERIFY_WRITE)) { + int ret = __put_user(fl64->l_type, &fl32->l_type); + ret |= __put_user(fl64->l_whence, &fl32->l_whence); + ret |= __put_user(fl64->l_start, &fl32->l_start); + ret |= __put_user(fl64->l_len, &fl32->l_len); + ret |= __put_user(fl64->l_pid, &fl32->l_pid); + return ret; } + return -EFAULT; } asmlinkage long sys32_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg) { - if (cmd >= F_GETLK64 && cmd <= F_SETLKW64) - return sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, arg); - return sys32_fcntl(fd, cmd, arg); + struct flock fl64; + mm_segment_t oldfs = get_fs(); + int ret = 0, origcmd; + unsigned long origarg; + + origcmd = cmd; + origarg = arg; + switch (cmd) { + case F_GETLK: + case F_SETLK: + case F_SETLKW: + ret = get_flock(&fl64, (struct flock32 *)arg); + arg = (unsigned long) &fl64; + set_fs(KERNEL_DS); + break; + case F_GETLK64: + cmd = F_GETLK; + goto cnv64; + case F_SETLK64: + cmd = F_SETLK; + goto cnv64; + case F_SETLKW64: + cmd = F_SETLKW; + cnv64: + ret = get_flock64((struct ia32_flock64 *)arg, &fl64); + arg = (unsigned long)&fl64; + set_fs(KERNEL_DS); + break; + } + if (!ret) + ret = sys_fcntl(fd, cmd, arg); + set_fs(oldfs); + if (origcmd == F_GETLK && !ret) + ret = put_flock(&fl64, (struct flock32 *)origarg); + else if (cmd == F_GETLK && !ret) + ret = put_flock64((struct ia32_flock64 *)origarg, &fl64); + return ret; } int sys32_ni_syscall(int call) @@ -1362,42 +1397,6 @@ return ret; } -/* - * Ooo, nasty. We need here to frob 32-bit unsigned longs to - * 64-bit unsigned longs. - */ - -static inline int -get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset) -{ - if (ufdset) { - unsigned long odd; - - if (verify_area(VERIFY_READ, ufdset, n*sizeof(u32))) - return -EFAULT; - - odd = n & 1UL; - n &= ~1UL; - while (n) { - unsigned long h, l; - __get_user(l, ufdset); - __get_user(h, ufdset+1); - ufdset += 2; - *fdset++ = h << 32 | l; - n -= 2; - } - if (odd) - __get_user(*fdset, ufdset); - } else { - /* Tricky, must clear full unsigned long in the - * kernel fdset at the end, this makes sure that - * actually happens. - */ - memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32)); - } - return 0; -} - extern asmlinkage long sys_sysfs(int option, unsigned long arg1, unsigned long arg2); @@ -1704,136 +1703,6 @@ return ret; } -extern asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); - -asmlinkage long sys32_setreuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid) -{ - uid_t sruid, seuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - return sys_setreuid(sruid, seuid); -} - -extern asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); - -asmlinkage long -sys32_setresuid(__kernel_uid_t32 ruid, __kernel_uid_t32 euid, - __kernel_uid_t32 suid) -{ - uid_t sruid, seuid, ssuid; - - sruid = (ruid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)ruid); - seuid = (euid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)euid); - ssuid = (suid == (__kernel_uid_t32)-1) ? ((uid_t)-1) : ((uid_t)suid); - return sys_setresuid(sruid, seuid, ssuid); -} - -extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); - -asmlinkage long -sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, - __kernel_uid_t32 *suid) -{ - uid_t a, b, c; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getresuid(&a, &b, &c); - set_fs (old_fs); - if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_setregid(gid_t rgid, gid_t egid); - -asmlinkage long -sys32_setregid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid) -{ - gid_t srgid, segid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - return sys_setregid(srgid, segid); -} - -extern asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); - -asmlinkage long -sys32_setresgid(__kernel_gid_t32 rgid, __kernel_gid_t32 egid, - __kernel_gid_t32 sgid) -{ - gid_t srgid, segid, ssgid; - - srgid = (rgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)rgid); - segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); - ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); - return sys_setresgid(srgid, segid, ssgid); -} - -extern asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); - -asmlinkage long -sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, - __kernel_gid_t32 *sgid) -{ - gid_t a, b, c; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getresgid(&a, &b, &c); - set_fs (old_fs); - if (!ret) { - ret = put_user (a, rgid); - ret |= put_user (b, egid); - ret |= put_user (c, sgid); - } - return ret; -} - -extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage long -sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - set_fs (KERNEL_DS); - ret = sys_getgroups(gidsetsize, gl); - set_fs (old_fs); - if (gidsetsize && ret > 0 && ret <= NGROUPS) - for (i = 0; i < ret; i++, grouplist++) - if (put_user (gl[i], grouplist)) - return -EFAULT; - return ret; -} - -extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist); - -asmlinkage long -sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist) -{ - gid_t gl[NGROUPS]; - int ret, i; - mm_segment_t old_fs = get_fs (); - - if ((unsigned) gidsetsize > NGROUPS) - return -EINVAL; - for (i = 0; i < gidsetsize; i++, grouplist++) - if (get_user (gl[i], grouplist)) - return -EFAULT; - set_fs (KERNEL_DS); - ret = sys_setgroups(gidsetsize, gl); - set_fs (old_fs); - return ret; -} - - extern void check_pending(int signum); asmlinkage long sys_utimes(char *, struct timeval *); @@ -1943,7 +1812,7 @@ int ret = sys_newuname(name); if (current->personality == PER_LINUX32 && !ret) { - ret = copy_to_user(name->machine, "i386\0\0", 8); + ret = copy_to_user(name->machine, "i686\0\0", 6); } return ret; } @@ -2164,7 +2033,7 @@ err=copy_to_user(name, &system_utsname, sizeof (*name)); up_read(&uts_sem); if (current->personality == PER_LINUX32) - err |= copy_to_user(&name->machine, "i386", 5); + err |= copy_to_user(&name->machine, "i686", 5); return err?-EFAULT:0; } @@ -2270,16 +2139,17 @@ asmlinkage int sys32_fork(struct pt_regs regs) { struct task_struct *p; - p = do_fork(SIGCHLD, regs.rsp, ®s, 0); + p = do_fork(SIGCHLD, regs.rsp, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } asmlinkage int sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs) { struct task_struct *p; + int *user_tid = (int *)regs.rdx; if (!newsp) newsp = regs.rsp; - p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0); + p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, user_tid); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -2296,7 +2166,7 @@ asmlinkage int sys32_vfork(struct pt_regs regs) { struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, ®s, 0); + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -2695,10 +2565,26 @@ return err; } +extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx); + +long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p) +{ + long ret; + aio_context_t ctx64; + mm_segment_t oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_io_setup(nr_reqs, &ctx64); + set_fs(oldfs); + /* truncating is ok because it's a user address */ + if (!ret) + ret = put_user((u32)ctx64, ctx32p); + return ret; +} + struct exec_domain ia32_exec_domain = { - name: "linux/x86", - pers_low: PER_LINUX32, - pers_high: PER_LINUX32, + .name = "linux/x86", + .pers_low = PER_LINUX32, + .pers_high = PER_LINUX32, }; static int __init ia32_init (void) diff -Nru a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile --- a/arch/x86_64/kernel/Makefile Tue Oct 15 20:29:19 2002 +++ b/arch/x86_64/kernel/Makefile Tue Oct 15 20:29:19 2002 @@ -2,15 +2,14 @@ # Makefile for the linux kernel. # -O_TARGET := kernel.o EXTRA_TARGETS := head.o head64.o init_task.o -export-objs := mtrr.o x8664_ksyms.o +export-objs := mtrr.o x8664_ksyms.o pci-gart.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \ pci-dma.o x8664_ksyms.o i387.o syscall.o vsyscall.o \ - setup64.o bluesmoke.o bootflag.o + setup64.o bluesmoke.o bootflag.o e820.o reboot.o obj-$(CONFIG_MTRR) += mtrr.o obj-$(CONFIG_X86_MSR) += msr.o @@ -18,9 +17,11 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o -#obj-$(CONFIG_ACPI) += acpi.o +obj-$(CONFIG_ACPI) += acpi.o #obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o +obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o EXTRA_AFLAGS := -traditional diff -Nru a/arch/x86_64/kernel/acpi.c b/arch/x86_64/kernel/acpi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/kernel/acpi.c Tue Oct 15 20:29:24 2002 @@ -0,0 +1,569 @@ +/* + * acpi.c - Architecture-Specific Low-Level ACPI Support + * + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * Copyright (C) 2001 Patrick Mochel + * Copyright (C) 2002 Andi Kleen, SuSE Labs (x86-64 port) + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int acpi_disabled; + +#define PREFIX "ACPI: " + + +/* -------------------------------------------------------------------------- + Boot-time Configuration + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_BOOT + +enum acpi_irq_model_id acpi_irq_model; + + +/* + * Use reserved fixmap pages for physical-to-virtual mappings of ACPI tables. + * Note that the same range is used for each table, so tables that need to + * persist should be memcpy'd. + */ + +extern unsigned long end_pfn; + +/* rely on all ACPI tables being in the direct mapping */ +char * +__acpi_map_table ( + unsigned long phys_addr, + unsigned long size) +{ + if (!phys_addr || !size) + return NULL; + + if (phys_addr < (end_pfn << PAGE_SHIFT)) + return __va(phys_addr); + + printk("acpi mapping beyond end_pfn: %lx > %lx\n", phys_addr, end_pfn<lapic_address) + acpi_lapic_addr = (u64) madt->lapic_address; + + printk(KERN_INFO PREFIX "Local APIC address 0x%08x\n", + madt->lapic_address); + + return 0; +} + + +static int __init +acpi_parse_lapic ( + acpi_table_entry_header *header) +{ + struct acpi_table_lapic *processor = NULL; + + processor = (struct acpi_table_lapic*) header; + if (!processor) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + mp_register_lapic ( + processor->id, /* APIC ID */ + processor->flags.enabled); /* Enabled? */ + + return 0; +} + + +static int __init +acpi_parse_lapic_addr_ovr ( + acpi_table_entry_header *header) +{ + struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; + + lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr*) header; + if (!lapic_addr_ovr) + return -EINVAL; + + acpi_lapic_addr = lapic_addr_ovr->address; + + return 0; +} + + +static int __init +acpi_parse_lapic_nmi ( + acpi_table_entry_header *header) +{ + struct acpi_table_lapic_nmi *lapic_nmi = NULL; + + lapic_nmi = (struct acpi_table_lapic_nmi*) header; + if (!lapic_nmi) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + if (lapic_nmi->lint != 1) + printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); + + return 0; +} + +#endif /*CONFIG_X86_LOCAL_APIC*/ + +#ifdef CONFIG_X86_IO_APIC + +int acpi_ioapic; + +static int __init +acpi_parse_ioapic ( + acpi_table_entry_header *header) +{ + struct acpi_table_ioapic *ioapic = NULL; + + ioapic = (struct acpi_table_ioapic*) header; + if (!ioapic) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + mp_register_ioapic ( + ioapic->id, + ioapic->address, + ioapic->global_irq_base); + + return 0; +} + + +static int __init +acpi_parse_int_src_ovr ( + acpi_table_entry_header *header) +{ + struct acpi_table_int_src_ovr *intsrc = NULL; + + intsrc = (struct acpi_table_int_src_ovr*) header; + if (!intsrc) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + mp_override_legacy_irq ( + intsrc->bus_irq, + intsrc->flags.polarity, + intsrc->flags.trigger, + intsrc->global_irq); + + return 0; +} + + +static int __init +acpi_parse_nmi_src ( + acpi_table_entry_header *header) +{ + struct acpi_table_nmi_src *nmi_src = NULL; + + nmi_src = (struct acpi_table_nmi_src*) header; + if (!nmi_src) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* TBD: Support nimsrc entries? */ + + return 0; +} + +#endif /*CONFIG_X86_IO_APIC*/ + +#ifdef CONFIG_HPET_TIMER +static int __init +acpi_parse_hpet ( + unsigned long phys_addr, + unsigned long size) +{ + struct acpi_table_hpet *hpet_tbl; + + hpet_tbl = __va(phys_addr); + + if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) { + printk(KERN_WARNING "acpi: HPET timers must be located in memory.\n"); + return -1; + } + + hpet.address = hpet_tbl->addr.addrl | ((long) hpet_tbl->addr.addrh << 32); + + printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n", hpet_tbl->id, hpet.address); + + return 0; +} +#endif + +static unsigned long __init +acpi_scan_rsdp ( + unsigned long start, + unsigned long length) +{ + unsigned long offset = 0; + unsigned long sig_len = sizeof("RSD PTR ") - 1; + + /* + * Scan all 16-byte boundaries of the physical memory region for the + * RSDP signature. + */ + for (offset = 0; offset < length; offset += 16) { + if (strncmp((char *) (start + offset), "RSD PTR ", sig_len)) + continue; + return (start + offset); + } + + return 0; +} + + +unsigned long __init +acpi_find_rsdp (void) +{ + unsigned long rsdp_phys = 0; + + /* + * Scan memory looking for the RSDP signature. First search EBDA (low + * memory) paragraphs and then search upper memory (E0000-FFFFF). + */ + rsdp_phys = acpi_scan_rsdp (0, 0x400); + if (!rsdp_phys) + rsdp_phys = acpi_scan_rsdp (0xE0000, 0xFFFFF); + + return rsdp_phys; +} + + +int __init +acpi_boot_init ( + char *cmdline) +{ + int result = 0; + + /* + * The default interrupt routing model is PIC (8259). This gets + * overriden if IOAPICs are enumerated (below). + */ + acpi_irq_model = ACPI_IRQ_MODEL_PIC; + + /* + * Initialize the ACPI boot-time table parser. + */ + result = acpi_table_init(cmdline); + if (result) + return result; + + result = acpi_blacklisted(); + if (result) { + acpi_disabled = 1; + return result; + } else + printk(KERN_NOTICE PREFIX "BIOS passes blacklist\n"); + + +#ifdef CONFIG_X86_LOCAL_APIC + + /* + * MADT + * ---- + * Parse the Multiple APIC Description Table (MADT), if exists. + * Note that this table provides platform SMP configuration + * information -- the successor to MPS tables. + */ + + result = acpi_table_parse(ACPI_APIC, acpi_parse_madt); + if (!result) { + printk(KERN_WARNING PREFIX "MADT not present\n"); + return 0; + } + else if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing MADT\n"); + return result; + } + else if (result > 1) + printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n"); + + /* + * Local APIC + * ---------- + * Note that the LAPIC address is obtained from the MADT (32-bit value) + * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). + */ + + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr); + if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); + return result; + } + + mp_register_lapic_address(acpi_lapic_addr); + + result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); + if (!result) { + printk(KERN_ERR PREFIX "No LAPIC entries present\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return -ENODEV; + } + else if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return result; + } + + result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); + if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return result; + } + + acpi_lapic = 1; + +#endif /*CONFIG_X86_LOCAL_APIC*/ + +#ifdef CONFIG_X86_IO_APIC + + /* + * I/O APIC + * -------- + */ + + result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); + if (!result) { + printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); + return -ENODEV; + } + else if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n"); + return result; + } + + /* Build a default routing table for legacy (ISA) interrupts. */ + mp_config_acpi_legacy_irqs(); + + result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); + if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return result; + } + + result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); + if (result < 0) { + printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return result; + } + + acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + + acpi_ioapic = 1; + +#endif /*CONFIG_X86_IO_APIC*/ + +#ifdef CONFIG_X86_LOCAL_APIC + if (acpi_lapic && acpi_ioapic) + smp_found_config = 1; +#endif + +#ifdef CONFIG_HPET_TIMER + result = acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + if (result < 0) + printk("ACPI: no HPET table found (%d).\n", result); +#endif + + return 0; +} + +#endif /*CONFIG_ACPI_BOOT*/ + + +/* -------------------------------------------------------------------------- + Low-Level Sleep Support + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_SLEEP + +#error not ported to x86-64 yet + +#define DEBUG + +#ifdef DEBUG +#include +#endif + +/* address in low memory of the wakeup routine. */ +unsigned long acpi_wakeup_address = 0; + +/* new page directory that we will be using */ +static pmd_t *pmd; + +/* saved page directory */ +static pmd_t saved_pmd; + +/* page which we'll use for the new page directory */ +static pte_t *ptep; + +extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); + +/* + * acpi_create_identity_pmd + * + * Create a new, identity mapped pmd. + * + * Do this by creating new page directory, and marking all the pages as R/W + * Then set it as the new Page Middle Directory. + * And, of course, flush the TLB so it takes effect. + * + * We save the address of the old one, for later restoration. + */ +static void acpi_create_identity_pmd (void) +{ + pgd_t *pgd; + int i; + + ptep = (pte_t*)__get_free_page(GFP_KERNEL); + + /* fill page with low mapping */ + for (i = 0; i < PTRS_PER_PTE; i++) + set_pte(ptep + i, mk_pte_phys(i << PAGE_SHIFT, PAGE_SHARED)); + + pgd = pgd_offset(current->active_mm, 0); + pmd = pmd_alloc(current->mm,pgd, 0); + + /* save the old pmd */ + saved_pmd = *pmd; + + /* set the new one */ + set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(ptep))); + + /* flush the TLB */ + local_flush_tlb(); +} + +/* + * acpi_restore_pmd + * + * Restore the old pmd saved by acpi_create_identity_pmd and + * free the page that said function alloc'd + */ +static void acpi_restore_pmd (void) +{ + set_pmd(pmd, saved_pmd); + local_flush_tlb(); + free_page((unsigned long)ptep); +} + +/** + * acpi_save_state_mem - save kernel state + * + * Create an identity mapped page table and copy the wakeup routine to + * low memory. + */ +int acpi_save_state_mem (void) +{ + acpi_create_identity_pmd(); + acpi_copy_wakeup_routine(acpi_wakeup_address); + + return 0; +} + +/** + * acpi_save_state_disk - save kernel state to disk + * + */ +int acpi_save_state_disk (void) +{ + return 1; +} + +/* + * acpi_restore_state + */ +void acpi_restore_state_mem (void) +{ + acpi_restore_pmd(); +} + +/** + * acpi_reserve_bootmem - do _very_ early ACPI initialisation + * + * We allocate a page in low memory for the wakeup + * routine for when we come back from a sleep state. The + * runtime allocator allows specification of <16M pages, but not + * <1M pages. + */ +void __init acpi_reserve_bootmem(void) +{ + acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); + printk(KERN_DEBUG "ACPI: have wakeup address 0x%8.8lx\n", acpi_wakeup_address); +} + +#endif /*CONFIG_ACPI_SLEEP*/ + +void acpi_pci_link_exit(void) {} diff -Nru a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/kernel/aperture.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,123 @@ +/* + * Firmware replacement code. + * + * Work around broken BIOSes that don't set an aperture. + * The IOMMU code needs an aperture even who no AGP is present in the system. + * Map the aperture over some low memory. This is cheaper than doing bounce + * buffering. The memory is lost. This is done at early boot because only + * the bootmem allocator can allocate 32+MB. + * + * Copyright 2002 Andi Kleen, SuSE Labs. + * $Id: aperture.c,v 1.2 2002/09/19 19:25:32 ak Exp $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int fallback_aper_order __initdata = 1; /* 64MB */ +int fallback_aper_force __initdata = 0; + +extern int no_iommu, force_mmu; + +/* This code runs before the PCI subsystem is initialized, so just + access the northbridge directly. */ + +#define NB_ID_3 (PCI_VENDOR_ID_AMD | (0x1103<<16)) + +static u32 __init allocate_aperture(void) +{ +#ifdef CONFIG_DISCONTIGMEM + pg_data_t *nd0 = NODE_DATA(0); +#else + pg_data_t *nd0 = &contig_page_data; +#endif + u32 aper_size; + void *p; + + if (fallback_aper_order > 7) + fallback_aper_order = 7; + aper_size = (32 * 1024 * 1024) << fallback_aper_order; + + /* + * Aperture has to be naturally aligned it seems. This means an + * 2GB aperture won't have much changes to succeed in the lower 4GB of + * memory. Unfortunately we cannot move it up because that would make + * the IOMMU useless. + */ + p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0); + if (!p || __pa(p)+aper_size > 0xffffffff) { + printk("Cannot allocate aperture memory hole (%p,%uK)\n", + p, aper_size>>10); + if (p) + free_bootmem((unsigned long)p, aper_size); + return 0; + } + printk("Mapping aperture over %d KB of RAM @ %lx\n", + aper_size >> 10, __pa(p)); + return (u32)__pa(p); +} + +void __init iommu_hole_init(void) +{ + int fix, num; + u32 aper_size, aper_alloc, aper_order; + u64 aper_base; + + if (no_iommu) + return; + if (end_pfn < (0xffffffff>>PAGE_SHIFT) && !force_mmu) + return; + + printk("Checking aperture...\n"); + + fix = 0; + for (num = 24; num < 32; num++) { + if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) + continue; + + aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7; + aper_size = (32 * 1024 * 1024) << aper_order; + aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff; + aper_base <<= 25; + + printk("CPU %d: aperture @ %Lx size %u KB\n", num-24, + aper_base, aper_size>>10); + if (!aper_base || aper_base + aper_size >= 0xffffffff) { + fix = 1; + break; + } + + if (e820_mapped(aper_base, aper_base + aper_size, E820_RAM)) { + printk("Aperture pointing to e820 RAM. Ignoring.\n"); + fix = 1; + break; + } + } + + if (!fix && !fallback_aper_force) + return; + + printk("Your BIOS is broken and doesn't leave a aperture memory hole\n"); + aper_alloc = allocate_aperture(); + if (!aper_alloc) + return; + + for (num = 24; num < 32; num++) { + if (read_pci_config(0, num, 3, 0x00) != NB_ID_3) + continue; + + /* Don't enable translation yet. That is done later. + Assume this BIOS didn't initialise the GART so + just overwrite all previous bits */ + write_pci_config(0, num, 3, 0x90, fallback_aper_order<<1); + write_pci_config(0, num, 3, 0x94, aper_alloc>>25); + } +} diff -Nru a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c --- a/arch/x86_64/kernel/apic.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/kernel/apic.c Tue Oct 15 20:29:12 2002 @@ -30,6 +30,8 @@ #include #include +int disable_apic_timer __initdata; + /* Using APIC to generate smp_local_timer_interrupt? */ int using_apic_timer = 0; @@ -598,7 +600,7 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model > 1) + if (boot_cpu_data.x86 > 6) break; goto no_apic; case X86_VENDOR_INTEL: @@ -640,6 +642,8 @@ if (nmi_watchdog != NMI_NONE) nmi_watchdog = NMI_LOCAL_APIC; + apic_pm_init1(); + printk("Found and enabled local APIC!\n"); return 0; @@ -695,59 +699,6 @@ } /* - * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts - * per second. We assume that the caller has already set up the local - * APIC. - * - * The APIC timer is not exactly sync with the external timer chip, it - * closely follows bus clocks. - */ - -/* - * The timer chip is already set up at HZ interrupts per second here, - * but we do not accept timer interrupts yet. We only allow the BP - * to calibrate. - */ -static unsigned int __init get_8254_timer_count(void) -{ - extern spinlock_t i8253_lock; - unsigned long flags; - - unsigned int count; - - spin_lock_irqsave(&i8253_lock, flags); - - outb_p(0x00, 0x43); - count = inb_p(0x40); - count |= inb_p(0x40) << 8; - - spin_unlock_irqrestore(&i8253_lock, flags); - - return count; -} - -void __init wait_8254_wraparound(void) -{ - unsigned int curr_count, prev_count=~0; - int delta; - - curr_count = get_8254_timer_count(); - - do { - prev_count = curr_count; - curr_count = get_8254_timer_count(); - delta = curr_count-prev_count; - - /* - * This limit for delta seems arbitrary, but it isn't, it's - * slightly above the level of error a buggy Mercury/Neptune - * chipset timer can cause. - */ - - } while (delta < 300); -} - -/* * This function sets up the local APIC timer, with a timeout of * 'clocks' APIC bus clock. During calibration we actually call * this function twice on the boot CPU, once with a bogus timeout @@ -779,52 +730,36 @@ apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR); } -void setup_APIC_timer(void * data) +static void setup_APIC_timer(unsigned int clocks) { - unsigned int clocks = (unsigned long) data, slice, t0, t1; unsigned long flags; - int delta; - local_save_flags(flags); - local_irq_enable(); - /* - * ok, Intel has some smart code in their APIC that knows - * if a CPU was in 'hlt' lowpower mode, and this increases - * its APIC arbitration priority. To avoid the external timer - * IRQ APIC event being in synchron with the APIC clock we - * introduce an interrupt skew to spread out timer events. - * - * The number of slices within a 'big' timeslice is smp_num_cpus+1 - */ - - slice = clocks / (smp_num_cpus+1); - printk("cpu: %d, clocks: %d, slice: %d\n", - smp_processor_id(), clocks, slice); - - /* - * Wait for IRQ0's slice: - */ - wait_8254_wraparound(); + local_irq_save(flags); +#if 0 + /* For some reasons this doesn't work on Simics, so fake it for now */ + if (strstr(boot_cpu_data.x86_model_id, "Screwdriver")) { __setup_APIC_LVTT(clocks); + return; + } +#endif - t0 = apic_read(APIC_TMICT)*APIC_DIVISOR; - /* Wait till TMCCT gets reloaded from TMICT... */ - do { - t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; - delta = (int)(t0 - t1 - slice*(smp_processor_id()+1)); - } while (delta >= 0); - /* Now wait for our slice for real. */ + /* wait for irq slice */ + { + int c1, c2; + outb_p(0x00, 0x43); + c2 = inb_p(0x40); + c2 |= inb_p(0x40) << 8; do { - t1 = apic_read(APIC_TMCCT)*APIC_DIVISOR; - delta = (int)(t0 - t1 - slice*(smp_processor_id()+1)); - } while (delta < 0); + c1 = c2; + outb_p(0x00, 0x43); + c2 = inb_p(0x40); + c2 |= inb_p(0x40) << 8; + } while (c2 - c1 < 300); + } __setup_APIC_LVTT(clocks); - printk("CPU%d\n", - smp_processor_id(), t0, t1, delta, slice, clocks); - local_irq_restore(flags); } @@ -841,16 +776,12 @@ * APIC irq that way. */ +#define TICK_COUNT 100000000 + int __init calibrate_APIC_clock(void) { - unsigned long t1 = 0, t2 = 0; - int tt1, tt2; + int apic, apic_start, tsc, tsc_start; int result; - int i; - const int LOOPS = HZ/10; - - printk("calibrating APIC timer ...\n"); - /* * Put whatever arbitrary (but long enough) timeout * value into the APIC clock, we just want to get the @@ -858,61 +789,31 @@ */ __setup_APIC_LVTT(1000000000); - /* - * The timer chip counts down to zero. Let's wait - * for a wraparound to start exact measurement: - * (the current tick might have been already half done) - */ - - wait_8254_wraparound(); - - /* - * We wrapped around just now. Let's start: - */ - if (cpu_has_tsc) - rdtscll(t1); - tt1 = apic_read(APIC_TMCCT); - - /* - * Let's wait LOOPS wraprounds: - */ - for (i = 0; i < LOOPS; i++) - wait_8254_wraparound(); - - tt2 = apic_read(APIC_TMCCT); - if (cpu_has_tsc) - rdtscll(t2); - - /* - * The APIC bus clock counter is 32 bits only, it - * might have overflown, but note that we use signed - * longs, thus no extra care needed. - * - * underflown to be exact, as the timer counts down ;) - */ - - result = (tt1-tt2)*APIC_DIVISOR/LOOPS; - - - printk("t1 = %ld t2 = %ld tt1 = %d tt2 = %d\n", t1, t2, tt1, tt2); + apic_start = apic_read(APIC_TMCCT); + rdtscl(tsc_start); + do { + apic = apic_read(APIC_TMCCT); + rdtscl(tsc); + } while ((tsc - tsc_start) < TICK_COUNT && (apic - apic_start) < TICK_COUNT); - if (cpu_has_tsc) - printk("..... CPU clock speed is %d.%04d MHz.\n", - ((int)(t2-t1)/LOOPS)/(1000000/HZ), - ((int)(t2-t1)/LOOPS)%(1000000/HZ)); + result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start); - printk("..... host bus clock speed is %d.%04d MHz.\n", - result/(1000000/HZ), - result%(1000000/HZ)); + printk("Detected %d.%03d MHz APIC timer.\n", + result / 1000 / 1000, result / 1000 % 1000); - return result; + return result * APIC_DIVISOR / HZ; } static unsigned int calibration_result; -void __init setup_APIC_clocks (void) +void __init setup_boot_APIC_clock (void) { + if (disable_apic_timer) { + printk("Disabling APIC timer\n"); + return; + } + printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; @@ -922,12 +823,16 @@ /* * Now set up the timer for real. */ - setup_APIC_timer((void *)(u64)calibration_result); + setup_APIC_timer(calibration_result); local_irq_enable(); +} - /* and update all other cpus */ - smp_call_function(setup_APIC_timer, (void *)(u64)calibration_result, 1, 1); +void __init setup_secondary_APIC_clock(void) +{ + local_irq_disable(); /* FIXME: Do we need this? --RR */ + setup_APIC_timer(calibration_result); + local_irq_enable(); } void __init disable_APIC_timer(void) @@ -1044,8 +949,6 @@ * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -unsigned int apic_timer_irqs [NR_CPUS]; - void smp_apic_timer_interrupt(struct pt_regs *regs) { int cpu = smp_processor_id(); @@ -1053,7 +956,7 @@ /* * the NMI deadlock-detector uses this. */ - apic_timer_irqs[cpu]++; + add_pda(apic_timer_irqs, 1); /* * NOTE! We'd better ACK the irq immediately, @@ -1065,12 +968,9 @@ * Besides, if we don't timer interrupts ignore the global * interrupt lock, which is the WrongThing (tm) to do. */ - irq_enter(cpu, 0); + irq_enter(); smp_local_timer_interrupt(regs); - irq_exit(cpu, 0); - - if (softirq_pending(cpu)) - do_softirq(); + irq_exit(); } /* @@ -1082,6 +982,7 @@ static unsigned long last_warning; static unsigned long skipped; + irq_enter(); /* * Check if this really is a spurious interrupt and ACK it * if it is a vectored one. Just in case... @@ -1099,6 +1000,7 @@ } else { skipped++; } + irq_exit(); } /* @@ -1109,6 +1011,7 @@ { unsigned int v, v1; + irq_enter(); /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); @@ -1126,16 +1029,23 @@ 6: Received illegal vector 7: Illegal register address */ - printk (KERN_ERR "APIC error on CPU%d: %02x(%02x)\n", + printk (KERN_INFO "APIC error on CPU%d: %02x(%02x)\n", smp_processor_id(), v , v1); + irq_exit(); } +int disable_apic __initdata; + /* * This initializes the IO-APIC and APIC hardware if this is * a UP kernel. */ int __init APIC_init_uniprocessor (void) { + if (disable_apic) { + printk(KERN_INFO "Apic disabled\n"); + return -1; + } if (!smp_found_config && !cpu_has_apic) return -1; @@ -1166,7 +1076,21 @@ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); #endif - setup_APIC_clocks(); + setup_boot_APIC_clock(); return 0; } + +static __init int setup_disableapic(char *str) +{ + disable_apic = 1; +} + +static __init int setup_noapictimer(char *str) +{ + disable_apic_timer = 1; +} + +__setup("disableapic", setup_disableapic); +__setup("noapictimer", setup_noapictimer); + diff -Nru a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c --- a/arch/x86_64/kernel/asm-offsets.c Tue Oct 15 20:29:17 2002 +++ b/arch/x86_64/kernel/asm-offsets.c Tue Oct 15 20:29:17 2002 @@ -24,15 +24,16 @@ ENTRY(state); ENTRY(flags); ENTRY(thread); + ENTRY(pid); BLANK(); #undef ENTRY -#define ENTRY(entry) DEFINE(threadinfo__ ## entry, offsetof(struct thread_info, entry)) +#define ENTRY(entry) DEFINE(threadinfo_ ## entry, offsetof(struct thread_info, entry)) ENTRY(flags); ENTRY(addr_limit); ENTRY(preempt_count); BLANK(); #undef ENTRY -#define ENTRY(entry) DEFINE(pda__ ## entry, offsetof(struct x8664_pda, entry)) +#define ENTRY(entry) DEFINE(pda_ ## entry, offsetof(struct x8664_pda, entry)) ENTRY(kernelstack); ENTRY(oldrsp); ENTRY(pcurrent); diff -Nru a/arch/x86_64/kernel/bluesmoke.c b/arch/x86_64/kernel/bluesmoke.c --- a/arch/x86_64/kernel/bluesmoke.c Tue Oct 15 20:29:21 2002 +++ b/arch/x86_64/kernel/bluesmoke.c Tue Oct 15 20:29:21 2002 @@ -39,7 +39,7 @@ recover=0; printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); - + preempt_disable(); for (i=0;i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long table_start, table_end; +extern char _end[]; + +extern struct resource code_resource, data_resource, vram_resource; + +/* Check for some hardcoded bad areas that early boot is not allowed to touch */ +static inline int bad_addr(unsigned long *addrp, unsigned long size) +{ + unsigned long addr = *addrp, last = addr + size; + + /* various gunk below that needed for SMP startup */ + if (addr < 7*PAGE_SIZE) { + *addrp = 7*PAGE_SIZE; + return 1; + } + +#if 0 + /* direct mapping tables of the kernel */ + if (last >= table_start<= INITRD_START && + addr < INITRD_START+INITRD_SIZE) { + *addrp = INITRD_START + INITRD_SIZE; + return 1; + } +#endif + /* kernel code + 640k memory hole (later should not be needed, but + be paranoid for now) */ + if (last >= 640*1024 && addr < __pa_symbol(&_end)) { + *addrp = __pa_symbol(&_end); + return 1; + } + /* XXX ramdisk image here? */ + return 0; +} + +int __init e820_mapped(unsigned long start, unsigned long end, int type) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + if (type && ei->type != type) + continue; + if (ei->addr >= end || ei->addr + ei->size < start) + continue; + return 1; + } + return 0; +} + +/* + * Find a free area in a specific range. + */ +unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + unsigned long addr = ei->addr, last; + if (ei->type != E820_RAM) + continue; + if (addr < start) + addr = start; + if (addr > ei->addr + ei->size) + continue; + while (bad_addr(&addr, size) && addr+size < ei->addr + ei->size) + ; + last = addr + size; + if (last > ei->addr + ei->size) + continue; + if (last > end) + continue; + return addr; + } + return -1UL; +} + +/* + * Free bootmem based on the e820 table for a node. + */ +void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + unsigned long last, addr; + + if (ei->type != E820_RAM || + ei->addr+ei->size <= start || + ei->addr > end) + continue; + + addr = round_up(ei->addr, PAGE_SIZE); + if (addr < start) + addr = start; + + last = round_down(ei->addr + ei->size, PAGE_SIZE); + if (last >= end) + last = end; + + if (last > addr && last-addr >= PAGE_SIZE) + free_bootmem_node(pgdat, addr, last-addr); + } +} + +/* + * Find the highest page frame number we have available + */ +void __init e820_end_of_ram(void) +{ + int i; + end_pfn = 0; + for (i = 0; i < e820.nr_map; i++) { + struct e820entry *ei = &e820.map[i]; + unsigned long start, end; + + /* count all types of areas for now to map ACPI easily */ + start = round_up(ei->addr, PAGE_SIZE); + end = round_down(ei->addr + ei->size, PAGE_SIZE); + if (start >= end) + continue; + if (end > end_pfn<>PAGE_SHIFT; + } + + if (end_pfn > MAXMEM >> PAGE_SHIFT) + end_pfn = MAXMEM >> PAGE_SHIFT; +} + +/* + * Mark e820 reserved areas as busy for the resource manager. + */ +void __init e820_reserve_resources(void) +{ + int i; + for (i = 0; i < e820.nr_map; i++) { + struct resource *res; + if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) + continue; + res = alloc_bootmem_low(sizeof(struct resource)); + switch (e820.map[i].type) { + case E820_RAM: res->name = "System RAM"; break; + case E820_ACPI: res->name = "ACPI Tables"; break; + case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; + default: res->name = "reserved"; + } + res->start = e820.map[i].addr; + res->end = res->start + e820.map[i].size - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + request_resource(&iomem_resource, res); + if (e820.map[i].type == E820_RAM) { + /* + * We dont't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } + } +} + +/* + * Add a memory region to the kernel e820 map. + */ +void __init add_memory_region(unsigned long start, unsigned long size, int type) +{ + int x = e820.nr_map; + + if (x == E820MAX) { + printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); + return; + } + + e820.map[x].addr = start; + e820.map[x].size = size; + e820.map[x].type = type; + e820.nr_map++; +} + +void __init e820_print_map(char *who) +{ + int i; + + for (i = 0; i < e820.nr_map; i++) { + printk(" %s: %016Lx - %016Lx ", who, + (unsigned long long) e820.map[i].addr, + (unsigned long long) (e820.map[i].addr + e820.map[i].size)); + switch (e820.map[i].type) { + case E820_RAM: printk("(usable)\n"); + break; + case E820_RESERVED: + printk("(reserved)\n"); + break; + case E820_ACPI: + printk("(ACPI data)\n"); + break; + case E820_NVS: + printk("(ACPI NVS)\n"); + break; + default: printk("type %u\n", e820.map[i].type); + break; + } + } +} + +/* + * Sanitize the BIOS e820 map. + * + * Some e820 responses include overlapping entries. The following + * replaces the original e820 map with a new one, removing overlaps. + * + */ +static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) +{ + struct change_member { + struct e820entry *pbios; /* pointer to original bios entry */ + unsigned long long addr; /* address for this change point */ + }; + static struct change_member change_point_list[2*E820MAX] __initdata; + static struct change_member *change_point[2*E820MAX] __initdata; + static struct e820entry *overlap_list[E820MAX] __initdata; + static struct e820entry new_bios[E820MAX] __initdata; + struct change_member *change_tmp; + unsigned long current_type, last_type; + unsigned long long last_addr; + int chgidx, still_changing; + int overlap_entries; + int new_bios_entry; + int old_nr, new_nr; + int i; + + /* + Visually we're performing the following (1,2,3,4 = memory types)... + + Sample memory map (w/overlaps): + ____22__________________ + ______________________4_ + ____1111________________ + _44_____________________ + 11111111________________ + ____________________33__ + ___________44___________ + __________33333_________ + ______________22________ + ___________________2222_ + _________111111111______ + _____________________11_ + _________________4______ + + Sanitized equivalent (no overlap): + 1_______________________ + _44_____________________ + ___1____________________ + ____22__________________ + ______11________________ + _________1______________ + __________3_____________ + ___________44___________ + _____________33_________ + _______________2________ + ________________1_______ + _________________4______ + ___________________2____ + ____________________33__ + ______________________4_ + */ + + /* if there's only one memory region, don't bother */ + if (*pnr_map < 2) + return -1; + + old_nr = *pnr_map; + + /* bail out if we find any unreasonable addresses in bios map */ + for (i=0; iaddr = biosmap[i].addr; + change_point[chgidx++]->pbios = &biosmap[i]; + change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; + change_point[chgidx++]->pbios = &biosmap[i]; + } + + /* sort change-point list by memory addresses (low -> high) */ + still_changing = 1; + while (still_changing) { + still_changing = 0; + for (i=1; i < 2*old_nr; i++) { + /* if > , swap */ + /* or, if current= & last=, swap */ + if ((change_point[i]->addr < change_point[i-1]->addr) || + ((change_point[i]->addr == change_point[i-1]->addr) && + (change_point[i]->addr == change_point[i]->pbios->addr) && + (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) + ) + { + change_tmp = change_point[i]; + change_point[i] = change_point[i-1]; + change_point[i-1] = change_tmp; + still_changing=1; + } + } + } + + /* create a new bios memory map, removing overlaps */ + overlap_entries=0; /* number of entries in the overlap table */ + new_bios_entry=0; /* index for creating new bios map entries */ + last_type = 0; /* start with undefined memory type */ + last_addr = 0; /* start with 0 as last starting address */ + /* loop through change-points, determining affect on the new bios map */ + for (chgidx=0; chgidx < 2*old_nr; chgidx++) + { + /* keep track of all overlapping bios entries */ + if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) + { + /* add map entry to overlap list (> 1 entry implies an overlap) */ + overlap_list[overlap_entries++]=change_point[chgidx]->pbios; + } + else + { + /* remove entry from list (order independent, so swap with last) */ + for (i=0; ipbios) + overlap_list[i] = overlap_list[overlap_entries-1]; + } + overlap_entries--; + } + /* if there are overlapping entries, decide which "type" to use */ + /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ + current_type = 0; + for (i=0; itype > current_type) + current_type = overlap_list[i]->type; + /* continue building up new bios map based on this information */ + if (current_type != last_type) { + if (last_type != 0) { + new_bios[new_bios_entry].size = + change_point[chgidx]->addr - last_addr; + /* move forward only if the new size was non-zero */ + if (new_bios[new_bios_entry].size != 0) + if (++new_bios_entry >= E820MAX) + break; /* no more space left for new bios entries */ + } + if (current_type != 0) { + new_bios[new_bios_entry].addr = change_point[chgidx]->addr; + new_bios[new_bios_entry].type = current_type; + last_addr=change_point[chgidx]->addr; + } + last_type = current_type; + } + } + new_nr = new_bios_entry; /* retain count for new bios entries */ + + /* copy new bios mapping into original location */ + memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); + *pnr_map = new_nr; + + return 0; +} + +/* + * Copy the BIOS e820 map into a safe place. + * + * Sanity-check it while we're at it.. + * + * If we're lucky and live on a modern system, the setup code + * will have given us a memory map that we can use to properly + * set up memory. If we aren't, we'll fake a memory map. + * + * We check to see that the memory map contains at least 2 elements + * before we'll use it, because the detection code in setup.S may + * not be perfect and most every PC known to man has two memory + * regions: one from 0 to 640k, and one from 1mb up. (The IBM + * thinkpad 560x, for example, does not cooperate with the memory + * detection code.) + */ +static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) +{ + /* Only one memory region (or negative)? Ignore it */ + if (nr_map < 2) + return -1; + + do { + unsigned long start = biosmap->addr; + unsigned long size = biosmap->size; + unsigned long end = start + size; + unsigned long type = biosmap->type; + + /* Overflow in 64 bits? Ignore the memory map. */ + if (start > end) + return -1; + + /* + * Some BIOSes claim RAM in the 640k - 1M region. + * Not right. Fix it up. + * + * This should be removed on Hammer which is supposed to not + * have non e820 covered ISA mappings there, but I had some strange + * problems so it stays for now. -AK + */ + if (type == E820_RAM) { + if (start < 0x100000ULL && end > 0xA0000ULL) { + if (start < 0xA0000ULL) + add_memory_region(start, 0xA0000ULL-start, type); + if (end <= 0x100000ULL) + continue; + start = 0x100000ULL; + size = end - start; + } + } + + add_memory_region(start, size, type); + } while (biosmap++,--nr_map); + return 0; +} + +void __init setup_memory_region(void) +{ + char *who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } + printk(KERN_INFO "BIOS-provided physical RAM map:\n"); + e820_print_map(who); +} + +static int usermem __initdata; + +void __init parse_memopt(char *p) +{ + if (!strncmp(p,"exactmap",8)) { + e820.nr_map = 0; + usermem = 1; + } else { + /* If the user specifies memory size, we + * blow away any automatically generated + * size + */ + unsigned long long start_at, mem_size; + + if (usermem == 0) { + /* first time in: zap the whitelist + * and reinitialize it with the + * standard low-memory region. + */ + e820.nr_map = 0; + usermem = 1; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + } + mem_size = memparse(p, &p); + if (*p == '@') + start_at = memparse(p+1, &p); + else { + start_at = HIGH_MEMORY; + mem_size -= HIGH_MEMORY; + usermem=0; + } + add_memory_region(start_at, mem_size, E820_RAM); + } + +} + +void __init print_user_map(void) +{ + if (usermem) { + printk(KERN_INFO "user-defined physical RAM map:\n"); + e820_print_map("user"); + } +} diff -Nru a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c --- a/arch/x86_64/kernel/early_printk.c Tue Oct 15 20:29:19 2002 +++ b/arch/x86_64/kernel/early_printk.c Tue Oct 15 20:29:19 2002 @@ -47,10 +47,10 @@ } static struct console early_vga_console = { - name: "earlyvga", - write: early_vga_write, - flags: CON_PRINTBUFFER, - index: -1, + .name = "earlyvga", + .write = early_vga_write, + .flags = CON_PRINTBUFFER, + .index = -1, }; /* Serial functions losely based on a similar package from Klaus P. Gerlicher */ @@ -138,10 +138,10 @@ } static struct console early_serial_console = { - name: "earlyser", - write: early_serial_write, - flags: CON_PRINTBUFFER, - index: -1, + .name = "earlyser", + .write = early_serial_write, + .flags = CON_PRINTBUFFER, + .index = -1, }; /* Direct interface for emergencies */ @@ -181,6 +181,9 @@ if (!strncmp(buf, "serial", 6)) { early_serial_init(buf + 6); early_console = &early_serial_console; + } else if (!strncmp(buf, "ttyS", 4)) { + early_serial_init(buf); + early_console = &early_serial_console; } else if (!strncmp(buf, "vga", 3)) { early_console = &early_vga_console; } else { diff -Nru a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S --- a/arch/x86_64/kernel/entry.S Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/kernel/entry.S Tue Oct 15 20:29:16 2002 @@ -84,7 +84,7 @@ xorq %rax, %rax pushq %rax /* ss */ pushq %rax /* rsp */ - pushq %rax /* eflags */ + pushq $(1<<9) /* eflags - interrupts on */ pushq $__KERNEL_CS /* cs */ pushq \child_rip /* rip */ pushq %rax /* orig rax */ @@ -236,21 +236,17 @@ * Has correct top of stack, but partial stack frame. */ ENTRY(int_ret_from_sys_call) - testl $3,CS-ARGOFFSET(%rsp) # kernel syscall? - je int_restore_args + cli + testl $3,CS-ARGOFFSET(%rsp) + je retint_restore_args movl $_TIF_ALLWORK_MASK,%edi /* edi: mask to check */ int_with_check: GET_THREAD_INFO(%rcx) - cli movl threadinfo_flags(%rcx),%edx andl %edi,%edx jnz int_careful -int_restore_swapgs: - swapgs -int_restore_args: - RESTORE_ARGS 0,8,0 - iretq + jmp retint_swapgs /* Either reschedule or signal or syscall exit tracking needed. */ /* First do a reschedule test. */ @@ -364,15 +360,11 @@ .macro interrupt func cld SAVE_ARGS -#ifdef CONFIG_PREEMPT - GET_THREAD_INFO(%rdx) - incl threadinfo_preempt_count(%rdx) -#endif leaq -ARGOFFSET(%rsp),%rdi # arg1 for handler testl $3,CS(%rdi) je 1f swapgs -1: addl $1,PDAREF(pda_irqcount) # XXX: should be merged with irq.c irqcount +1: addl $1,PDAREF(pda_irqcount) # RED-PEN should check preempt count movq PDAREF(pda_irqstackptr),%rax cmoveq %rax,%rsp pushq %rdi # save old stack @@ -389,9 +381,6 @@ leaq ARGOFFSET(%rdi),%rsp exit_intr: GET_THREAD_INFO(%rcx) -#ifdef CONFIG_PREEMPT - decl threadinfo_preempt_count(%rcx) -#endif testl $3,CS-ARGOFFSET(%rsp) je retint_kernel @@ -407,11 +396,24 @@ andl %edi,%edx jnz retint_careful retint_swapgs: + cli swapgs retint_restore_args: + cli RESTORE_ARGS 0,8,0 +iret_label: iretq + .section __ex_table,"a" + .quad iret_label,bad_iret + .previous + .section .fixup,"ax" + /* force a signal here? this matches i386 behaviour */ +bad_iret: + movq $-9999,%rdi /* better code? */ + jmp do_exit + .previous + /* edi: workmask, edx: work */ retint_careful: bt $TIF_NEED_RESCHED,%edx @@ -448,9 +450,8 @@ jnz retint_restore_args bt $TIF_NEED_RESCHED,threadinfo_flags(%rcx) jnc retint_restore_args - movl PDAREF(pda___local_bh_count),%eax - addl PDAREF(pda___local_irq_count),%eax - jnz retint_restore_args + bt $9,EFLAGS-ARGOFFSET(%rsp) /* interrupts off? */ + jc retint_restore_args movl $PREEMPT_ACTIVE,threadinfo_preempt_count(%rcx) sti call schedule @@ -513,11 +514,6 @@ */ ALIGN error_entry: - testl $3,24(%rsp) - je error_kernelspace - swapgs -error_kernelspace: - sti /* rdi slot contains rax, oldrax contains error code */ pushq %rsi movq 8(%rsp),%rsi /* load rax */ @@ -530,17 +526,25 @@ pushq %r11 cld SAVE_REST + testl $3,CS(%rsp) + je error_kernelspace +error_swapgs: + xorl %ebx,%ebx + swapgs +error_sti: + sti movq %rdi,RDI(%rsp) movq %rsp,%rdi movq ORIG_RAX(%rsp),%rsi /* get error code */ movq $-1,ORIG_RAX(%rsp) call *%rax error_exit: + movl %ebx,%eax RESTORE_REST cli GET_THREAD_INFO(%rcx) - testl $3,CS-ARGOFFSET(%rsp) - je retint_kernel + testl %eax,%eax + jne retint_kernel movl threadinfo_flags(%rcx),%edx movl $_TIF_WORK_MASK,%edi andl %edi,%edx @@ -549,6 +553,39 @@ RESTORE_ARGS 0,8,0 iretq +error_kernelspace: + /* There are two places in the kernel that can potentially fault with + usergs. Handle them here. */ + cmpq $iret_label,RIP(%rsp) + je error_swapgs + cmpq $gs_change,RIP(%rsp) + je error_swapgs + movl $1,%ebx + jmp error_sti + + /* Reload gs selector with exception handling */ + /* edi: new selector */ +ENTRY(load_gs_index) + pushf + cli + swapgs +gs_change: + movl %edi,%gs +2: swapgs + popf + ret + + .section __ex_table,"a" + .align 8 + .quad gs_change,bad_gs + .previous + .section .fixup,"ax" +bad_gs: + xorl %eax,%eax + movl %eax,%gs + jmp 2b + .previous + /* * Create a kernel thread. * @@ -564,7 +601,7 @@ # rdi: flags, rsi: usp, rdx: will be &pt_regs movq %rdx,%rdi - orq kernel_thread_flags(%rip), %rdi + orq kernel_thread_flags(%rip),%rdi movq $-1, %rsi movq %rsp, %rdx @@ -573,8 +610,9 @@ xorl %edi,%edi cmpq $-1000,%rax - cmovb %rdi,%rax - movq %rax,RAX(%rsp) + jnb 1f + movl tsk_pid(%rax),%eax +1: movq %rax,RAX(%rsp) /* * It isn't worth to check for reschedule here, @@ -648,18 +686,19 @@ zeroentry do_simd_coprocessor_error ENTRY(device_not_available) - testl $3,8(%rsp) + pushq $-1 #error code + SAVE_ALL + movl $1,%ebx + testl $3,CS(%rsp) je 1f + xorl %ebx,%ebx swapgs -1: pushq $-1 #error code - SAVE_ALL - movq %cr0,%rax +1: movq %cr0,%rax leaq math_state_restore(%rip),%rcx - leaq math_emulate(%rip),%rbx + leaq math_emulate(%rip),%rdx testl $0x4,%eax - cmoveq %rcx,%rbx - preempt_stop - call *%rbx + cmoveq %rcx,%rdx + call *%rdx jmp error_exit ENTRY(debug) diff -Nru a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S --- a/arch/x86_64/kernel/head.S Tue Oct 15 20:29:17 2002 +++ b/arch/x86_64/kernel/head.S Tue Oct 15 20:29:17 2002 @@ -159,7 +159,7 @@ * addresses where we're currently running on. We have to do that here * because in 32bit we couldn't load a 64bit linear address. */ - lgdt pGDT64 + lgdt cpu_gdt_descr /* * Setup up a dummy PDA. this is just for some early bootup code @@ -276,7 +276,7 @@ .org 0x5000 ENTRY(level2_kernel_pgt) /* 40MB kernel mapping. The kernel code cannot be bigger than that. - When you change this change KERNEL_TEXT_SIZE in pgtable.h too. */ + When you change this change KERNEL_TEXT_SIZE in page.h too. */ /* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */ .quad 0x0000000000000183 .quad 0x0000000000200183 @@ -320,16 +320,18 @@ .org 0xb000 .data -.globl gdt - - .word 0 .align 16 - .word 0 -pGDT64: - .word gdt_end-gdt_table + .globl cpu_gdt_descr +cpu_gdt_descr: + .word gdt_end-cpu_gdt_table gdt: - .quad gdt_table - + .quad cpu_gdt_table +#ifdef CONFIG_SMP + .rept NR_CPUS-1 + .word 0 + .quad 0 + .endr +#endif .align 64 /* cacheline aligned */ ENTRY(gdt_table32) @@ -344,8 +346,12 @@ */ .align 64 /* cacheline aligned, keep this synchronized with asm/desc.h */ -ENTRY(gdt_table) - .quad 0x0000000000000000 /* This one is magic */ + +/* The TLS descriptors are currently at a different place compared to i386. + Hopefully nobody expects them at a fixed place (Wine?) */ + +ENTRY(cpu_gdt_table) + .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* unused */ .quad 0x00af9a000000ffff /* __KERNEL_CS */ .quad 0x00cf92000000ffff /* __KERNEL_DS */ @@ -358,14 +364,19 @@ .word 0x00CF # granularity = 4096, 386 # (+5th nibble of limit) /* __KERNEL32_CS */ - - .globl tss_start -tss_start: - .rept NR_CPUS - .quad 0,0,0,0,0,0,0,0 /* TSS/LDT/per cpu entries. filled in later */ - .endr + .quad 0,0 /* TSS */ + .quad 0 /* LDT */ + .quad 0,0,0 /* three TLS descriptors */ + .quad 0,0 /* pad to cache line boundary */ gdt_end: .globl gdt_end + + /* GDTs of other CPUs */ +#ifdef CONFIG_SMP + .rept NR_CPUS-1 + .quad 0,0,0,0,0,0,0,0,0,0,0 + .endr +#endif .align 64 ENTRY(idt_table) diff -Nru a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c --- a/arch/x86_64/kernel/head64.c Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/kernel/head64.c Tue Oct 15 20:29:16 2002 @@ -71,6 +71,7 @@ } extern void start_kernel(void), pda_init(int), setup_early_printk(char *); +extern int disable_apic; void __init x86_64_start_kernel(char * real_mode_data) { @@ -82,6 +83,10 @@ s = strstr(saved_command_line, "earlyprintk="); if (s != NULL) setup_early_printk(s+12); +#ifdef CONFIG_X86_IO_APIC + if (strstr(saved_command_line, "disableapic")) + disable_apic = 1; +#endif setup_boot_cpu_data(); start_kernel(); } diff -Nru a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c --- a/arch/x86_64/kernel/i8259.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/kernel/i8259.c Tue Oct 15 20:29:12 2002 @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -120,7 +119,8 @@ BUG(); } - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && + irq_desc[irq].action) enable_8259A_irq(irq); } @@ -319,18 +319,6 @@ goto handle_real_irq; } } - -static struct device device_i8259A = { - name: "i8259A", - bus_id: "0020", -}; - -static int __init init_8259A_devicefs(void) -{ - return register_sys_device(&device_i8259A); -} - -__initcall(init_8259A_devicefs); void __init init_8259A(int auto_eoi) { diff -Nru a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c --- a/arch/x86_64/kernel/init_task.c Tue Oct 15 20:29:17 2002 +++ b/arch/x86_64/kernel/init_task.c Tue Oct 15 20:29:17 2002 @@ -10,7 +10,7 @@ static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); struct mm_struct init_mm = INIT_MM(init_mm); /* diff -Nru a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c --- a/arch/x86_64/kernel/io_apic.c Tue Oct 15 20:29:17 2002 +++ b/arch/x86_64/kernel/io_apic.c Tue Oct 15 20:29:17 2002 @@ -17,6 +17,7 @@ * thanks to Eric Gilmore * and Rolf G. Tews * for testing these extensively + * Paul Diefenbaugh : Added full ACPI support */ #include @@ -28,6 +29,7 @@ #include #include #include +#include #include #include @@ -746,7 +748,8 @@ (reg_01.entries != 0x1f) && /* dual Xeon boards */ (reg_01.entries != 0x22) && /* bigger Xeon boards */ (reg_01.entries != 0x2E) && - (reg_01.entries != 0x3F) + (reg_01.entries != 0x3F) && + (reg_01.entries != 0x03) ) UNEXPECTED_IO_APIC(); @@ -1014,6 +1017,8 @@ unsigned char old_id; unsigned long flags; + if (acpi_ioapic) return; /* ACPI does that already */ + /* * Set the IOAPIC ID to the value stored in the MPC table. */ @@ -1104,7 +1109,7 @@ { unsigned int t1 = jiffies; - sti(); + local_irq_enable(); /* Let ten ticks pass... */ mdelay((10 * 1000) / HZ); @@ -1117,7 +1122,6 @@ */ if (jiffies - t1 > 4) return 1; - return 0; } @@ -1376,7 +1380,7 @@ end_lapic_irq }; -static void enable_NMI_through_LVT0 (void * dummy) +void enable_NMI_through_LVT0 (void * dummy) { unsigned int v, ver; @@ -1401,7 +1405,6 @@ */ printk(KERN_INFO "activating NMI Watchdog ..."); - smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1); enable_NMI_through_LVT0(NULL); printk(" done.\n"); @@ -1477,7 +1480,6 @@ */ static inline void check_timer(void) { - extern int timer_ack; int pin1, pin2; int vector; @@ -1497,7 +1499,6 @@ */ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); init_8259A(1); - timer_ack = 1; enable_8259A_irq(0); pin1 = find_isa_irq_pin(0, mp_INT); @@ -1605,8 +1606,7 @@ printk("ENABLING IO-APIC IRQs\n"); /* - * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS - * mptable: + * Set up the IO-APIC IRQ routing table. */ setup_ioapic_ids_from_mpc(); sync_Arb_IDs(); @@ -1615,3 +1615,175 @@ check_timer(); print_IO_APIC(); } + +/* Ensure the ACPI SCI interrupt level is active low, edge-triggered */ + +void __init mp_config_ioapic_for_sci(int irq) +{ +#if 0 /* fixme */ + int ioapic; + int ioapic_pin; + + ioapic = mp_find_ioapic(irq); + + ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; + + io_apic_set_pci_routing(ioapic, ioapic_pin, irq); +#endif +} + + +/* -------------------------------------------------------------------------- + ACPI-based IOAPIC Configuration + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_BOOT + +#define IO_APIC_MAX_ID 15 + +int __init io_apic_get_unique_id (int ioapic, int apic_id) +{ + struct IO_APIC_reg_00 reg_00; + static unsigned long apic_id_map = 0; + unsigned long flags; + int i = 0; + + /* + * The P4 platform supports up to 256 APIC IDs on two separate APIC + * buses (one for LAPICs, one for IOAPICs), where predecessors only + * supports up to 16 on one shared APIC bus. + * + * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full + * advantage of new APIC bus architecture. + */ + + if (!apic_id_map) + apic_id_map = phys_cpu_present_map; + + spin_lock_irqsave(&ioapic_lock, flags); + *(int *)®_00 = io_apic_read(ioapic, 0); + spin_unlock_irqrestore(&ioapic_lock, flags); + + if (apic_id >= IO_APIC_MAX_ID) { + printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " + "%d\n", ioapic, apic_id, reg_00.ID); + apic_id = reg_00.ID; + } + + /* + * Every APIC in a system must have a unique ID or we get lots of nice + * 'stuck on smp_invalidate_needed IPI wait' messages. + */ + if (apic_id_map & (1 << apic_id)) { + + for (i = 0; i < IO_APIC_MAX_ID; i++) { + if (!(apic_id_map & (1 << i))) + break; + } + + if (i == IO_APIC_MAX_ID) + panic("Max apic_id exceeded!\n"); + + printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " + "trying %d\n", ioapic, apic_id, i); + + apic_id = i; + } + + apic_id_map |= (1 << apic_id); + + if (reg_00.ID != apic_id) { + reg_00.ID = apic_id; + + spin_lock_irqsave(&ioapic_lock, flags); + io_apic_write(ioapic, 0, *(int *)®_00); + *(int *)®_00 = io_apic_read(ioapic, 0); + spin_unlock_irqrestore(&ioapic_lock, flags); + + /* Sanity check */ + if (reg_00.ID != apic_id) + panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); + } + + printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); + + return apic_id; +} + + +int __init io_apic_get_version (int ioapic) +{ + struct IO_APIC_reg_01 reg_01; + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + *(int *)®_01 = io_apic_read(ioapic, 1); + spin_unlock_irqrestore(&ioapic_lock, flags); + + return reg_01.version; +} + + +int __init io_apic_get_redir_entries (int ioapic) +{ + struct IO_APIC_reg_01 reg_01; + unsigned long flags; + + spin_lock_irqsave(&ioapic_lock, flags); + *(int *)®_01 = io_apic_read(ioapic, 1); + spin_unlock_irqrestore(&ioapic_lock, flags); + + return reg_01.entries; +} + + +int io_apic_set_pci_routing (int ioapic, int pin, int irq) +{ + struct IO_APIC_route_entry entry; + unsigned long flags; + + if (!IO_APIC_IRQ(irq)) { + printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0/n", + ioapic); + return -EINVAL; + } + + /* + * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. + * Note that we mask (disable) IRQs now -- these get enabled when the + * corresponding device driver registers for this IRQ. + */ + + memset(&entry,0,sizeof(entry)); + + entry.delivery_mode = dest_LowestPrio; + entry.dest_mode = INT_DELIVERY_MODE; + entry.dest.logical.logical_dest = TARGET_CPUS; + entry.mask = 1; /* Disabled (masked) */ + entry.trigger = 1; /* Level sensitive */ + entry.polarity = 1; /* Low active */ + + add_pin_to_irq(irq, ioapic, pin); + + entry.vector = assign_irq_vector(irq); + + printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " + "IRQ %d)\n", ioapic, + mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq); + + irq_desc[irq].handler = &ioapic_level_irq_type; + + set_intr_gate(entry.vector, interrupt[irq]); + + if (!ioapic && (irq < 16)) + disable_8259A_irq(irq); + + spin_lock_irqsave(&ioapic_lock, flags); + io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1)); + io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0)); + spin_unlock_irqrestore(&ioapic_lock, flags); + + return entry.vector; +} + +#endif /*CONFIG_ACPI_BOOT*/ diff -Nru a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c --- a/arch/x86_64/kernel/ioport.c Tue Oct 15 20:29:14 2002 +++ b/arch/x86_64/kernel/ioport.c Tue Oct 15 20:29:14 2002 @@ -56,17 +56,21 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) { struct thread_struct * t = ¤t->thread; - struct tss_struct * tss = init_tss + smp_processor_id(); + struct tss_struct * tss; + int ret = 0; if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32)) return -EINVAL; if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; + tss = init_tss + get_cpu(); if (!t->io_bitmap_ptr) { t->io_bitmap_ptr = kmalloc((IO_BITMAP_SIZE+1)*4, GFP_KERNEL); - if (!t->io_bitmap_ptr) - return -ENOMEM; + if (!t->io_bitmap_ptr) { + ret = -ENOMEM; + goto out; + } memset(t->io_bitmap_ptr,0xff,(IO_BITMAP_SIZE+1)*4); tss->io_map_base = IO_BITMAP_OFFSET; } @@ -77,7 +81,9 @@ set_bitmap((unsigned long *) t->io_bitmap_ptr, from, num, !turn_on); set_bitmap((unsigned long *) tss->io_bitmap, from, num, !turn_on); - return 0; + out: + put_cpu(); + return ret; } /* diff -Nru a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c --- a/arch/x86_64/kernel/irq.c Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/kernel/irq.c Tue Oct 15 20:29:16 2002 @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -138,7 +137,7 @@ struct irqaction * action; seq_printf(p, " "); - for (j=0; jtypename); seq_printf(p, " %s", action->name); @@ -162,13 +161,13 @@ seq_putc(p, '\n'); } seq_printf(p, "NMI: "); - for (j = 0; j < smp_num_cpus; j++) - seq_printf(p, "%10u ", cpu_pda[cpu_logical_map(j)].__nmi_count); + for_each_cpu(j) + seq_printf(p, "%10u ", cpu_pda[j].__nmi_count); seq_putc(p, '\n'); #if CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); - for (j = 0; j < smp_num_cpus; j++) - seq_printf(p, "%10u ", apic_timer_irqs[cpu_logical_map(j)]); + for_each_cpu(j) + seq_printf(p, "%10u ", cpu_pda[j].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); @@ -180,250 +179,12 @@ return 0; } -/* - * Global interrupt locks for SMP. Allow interrupts to come in on any - * CPU, yet make cli/sti act globally to protect critical regions.. - */ - #ifdef CONFIG_SMP -unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */ - -extern void show_stack(unsigned long* esp); - - -/* XXX: this unfortunately doesn't support irqstacks currently, should check the other PDAs */ -static void show(char * str) -{ - int i; - int cpu = smp_processor_id(); - - printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [",irqs_running()); - for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_irq_count(i)); - printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); - for(i=0;i < smp_num_cpus;i++) - printk(" %d",local_bh_count(i)); - - printk(" ]\nStack dumps:"); - for(i = 0; i < smp_num_cpus; i++) { - unsigned long esp; - if (i == cpu) - continue; - printk("\nCPU %d:",i); - esp = init_tss[i].rsp0; - if (!esp) { - /* tss->esp0 is set to NULL in cpu_init(), - * it's initialized when the cpu returns to user - * space. -- manfreds - */ - printk(" "); - continue; - } - esp &= ~(THREAD_SIZE-1); - esp += sizeof(struct thread_info); - show_stack((void*)esp); - } - printk("\nCPU %d:",cpu); - show_stack(NULL); - printk("\n"); -} - -#define MAXCOUNT 100000000 - -/* - * I had a lockup scenario where a tight loop doing - * spin_unlock()/spin_lock() on CPU#1 was racing with - * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but - * apparently the spin_unlock() information did not make it - * through to CPU#0 ... nasty, is this by design, do we have to limit - * 'memory update oscillation frequency' artificially like here? - * - * Such 'high frequency update' races can be avoided by careful design, but - * some of our major constructs like spinlocks use similar techniques, - * it would be nice to clarify this issue. Set this define to 0 if you - * want to check whether your system freezes. I suspect the delay done - * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but - * i thought that such things are guaranteed by design, since we use - * the 'LOCK' prefix. - */ -#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0 - -#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND -# define SYNC_OTHER_CORES(x) udelay(x+1) -#else -/* - * We have to allow irqs to arrive between local_irq_enable and local_irq_disable - */ -# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") -#endif - -static inline void wait_on_irq(int cpu) -{ - int count = MAXCOUNT; - - for (;;) { - - /* - * Wait until all interrupts are gone. Wait - * for bottom half handlers unless we're - * already executing in one.. - */ - if (!irqs_running()) - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) - break; - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - clear_bit(0,&global_irq_lock); - - for (;;) { - if (!--count) { - show("wait_on_irq"); - count = ~0; - } - local_irq_enable(); - SYNC_OTHER_CORES(cpu); - local_irq_disable(); - if (irqs_running()) - continue; - if (global_irq_lock) - continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) - continue; - if (!test_and_set_bit(0,&global_irq_lock)) - break; - } - } -} - -/* - * This is called when we want to synchronize with - * interrupts. We may for example tell a device to - * stop sending interrupts: but to make sure there - * are no interrupts that are executing on another - * CPU we need to call this function. - */ -void synchronize_irq(void) -{ - if (irqs_running()) { - /* Stupid approach */ - cli(); - sti(); - } -} - -static inline void get_irqlock(int cpu) -{ - if (test_and_set_bit(0,&global_irq_lock)) { - /* do we already hold the lock? */ - if ((unsigned char) cpu == global_irq_holder) - return; - /* Uhhuh.. Somebody else got it. Wait.. */ - do { - do { - rep_nop(); - } while (test_bit(0,&global_irq_lock)); - } while (test_and_set_bit(0,&global_irq_lock)); - } - /* - * We also to make sure that nobody else is running - * in an interrupt context. - */ - wait_on_irq(cpu); - - /* - * Ok, finally.. - */ - global_irq_holder = cpu; -} - -#define EFLAGS_IF_SHIFT 9 - -/* - * A global "cli()" while in an interrupt context - * turns into just a local cli(). Interrupts - * should use spinlocks for the (very unlikely) - * case that they ever want to protect against - * each other. - * - * If we already have local interrupts disabled, - * this will not turn a local disable into a - * global one (problems with spinlocks: this makes - * save_flags+cli+sti usable inside a spinlock). - */ -void __global_cli(void) -{ - unsigned long flags; - - local_save_flags(flags); - if (flags & (1 << EFLAGS_IF_SHIFT)) { - int cpu = smp_processor_id(); - local_irq_disable(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); - } -} - -void __global_sti(void) +inline void synchronize_irq(unsigned int irq) { - int cpu = smp_processor_id(); - - if (!local_irq_count(cpu)) - release_irqlock(cpu); - local_irq_enable(); + while (irq_desc[irq].status & IRQ_INPROGRESS) + cpu_relax(); } - -/* - * SMP flags value to restore to: - * 0 - global cli - * 1 - global sti - * 2 - local cli - * 3 - local sti - */ -unsigned long __global_save_flags(void) -{ - int retval; - int local_enabled; - unsigned long flags; - int cpu = smp_processor_id(); - - local_save_flags(flags); - local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; - /* default to local */ - retval = 2 + local_enabled; - - /* check for global flags if we're not in an interrupt */ - if (!local_irq_count(cpu)) { - if (local_enabled) - retval = 1; - if (global_irq_holder == cpu) - retval = 0; - } - return retval; -} - -void __global_restore_flags(unsigned long flags) -{ - switch (flags) { - case 0: - __global_cli(); - break; - case 1: - __global_sti(); - break; - case 2: - local_irq_disable(); - break; - case 3: - local_irq_enable(); - break; - default: - printk("global_restore_flags: %08lx (%08lx)\n", - flags, (&flags)[-1]); - } -} - #endif /* @@ -435,11 +196,7 @@ */ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { - int status; - - irq_enter(0, irq); - - status = 1; /* Force the "do bottom halves" bit */ + int status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); @@ -453,8 +210,6 @@ add_interrupt_randomness(irq); local_irq_disable(); - irq_exit(0, irq); - return status; } @@ -474,7 +229,7 @@ * Unlike disable_irq(), this function does not ensure existing * instances of the IRQ handler have completed before returning. * - * This function may be called from IRQ context. + * This function must not be called from IRQ context. */ inline void disable_irq_nosync(unsigned int irq) @@ -506,13 +261,7 @@ void disable_irq(unsigned int irq) { disable_irq_nosync(irq); - - if (!local_irq_count(smp_processor_id())) { - do { - barrier(); - cpu_relax(); - } while (irq_desc[irq].status & IRQ_INPROGRESS); - } + synchronize_irq(irq); } /** @@ -578,6 +327,7 @@ if (irq > 256) BUG(); + irq_enter(); kstat.irqs[cpu][irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); @@ -593,7 +343,7 @@ * use the action we have. */ action = NULL; - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) { action = desc->action; status &= ~IRQ_PENDING; /* we commit to handling */ status |= IRQ_INPROGRESS; /* we are handling it */ @@ -606,7 +356,7 @@ a different instance of this same irq, the other processor will take care of it. */ - if (!action) + if (unlikely(!action)) goto out; /* @@ -624,7 +374,7 @@ handle_IRQ_event(irq, regs, action); spin_lock(&desc->lock); - if (!(desc->status & IRQ_PENDING)) + if (unlikely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; } @@ -638,8 +388,7 @@ desc->handler->end(irq); spin_unlock(&desc->lock); - if (softirq_pending(cpu)) - do_softirq(); + irq_exit(); return 1; } @@ -703,7 +452,7 @@ return -EINVAL; action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); + kmalloc(sizeof(struct irqaction), GFP_ATOMIC); if (!action) return -ENOMEM; @@ -766,13 +515,7 @@ } spin_unlock_irqrestore(&desc->lock,flags); -#ifdef CONFIG_SMP - /* Wait to make sure it's not being used on another CPU */ - while (desc->status & IRQ_INPROGRESS) { - barrier(); - cpu_relax(); - } -#endif + synchronize_irq(irq); kfree(action); return; } @@ -824,7 +567,7 @@ /* Wait for longstanding interrupts to trigger. */ for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) - /* about 20ms delay */ synchronize_irq(); + /* about 20ms delay */ barrier(); /* * enable any unassigned irqs @@ -847,7 +590,7 @@ * Wait for spurious interrupts to trigger */ for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) - /* about 100ms delay */ synchronize_irq(); + /* about 100ms delay */ barrier(); /* * Now filter out any obviously spurious interrupts diff -Nru a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c --- a/arch/x86_64/kernel/ldt.c Tue Oct 15 20:29:21 2002 +++ b/arch/x86_64/kernel/ldt.c Tue Oct 15 20:29:21 2002 @@ -22,32 +22,13 @@ #include #include -void load_gs_index(unsigned gs) -{ - int access; - struct task_struct *me = current; - if (me->mm) - read_lock(&me->mm->context.ldtlock); - asm volatile("pushf\n\t" - "cli\n\t" - "swapgs\n\t" - "lar %1,%0\n\t" - "jnz 1f\n\t" - "movl %1,%%eax\n\t" - "movl %%eax,%%gs\n\t" - "jmp 2f\n\t" - "1: movl %2,%%gs\n\t" - "2: swapgs\n\t" - "popf" : "=g" (access) : "g" (gs), "r" (0) : "rax"); - if (me->mm) - read_unlock(&me->mm->context.ldtlock); -} +extern void load_gs_index(unsigned gs); #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ -static void flush_ldt(void *mm) +static void flush_ldt(void *null) { - if (current->mm) - load_LDT(¤t->mm->context); + if (current->active_mm) + load_LDT(¤t->active_mm->context); } #endif @@ -75,15 +56,18 @@ memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); wmb(); pc->ldt = newldt; + wmb(); pc->size = mincount; + wmb(); if (reload) { load_LDT(pc); #ifdef CONFIG_SMP + preempt_disable(); if (current->mm->cpu_vm_mask != (1< PAGE_SIZE) vfree(oldldt); @@ -96,11 +80,8 @@ 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; + if (err < 0) return err; - } memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); return 0; } @@ -187,7 +168,7 @@ struct mm_struct * mm = me->mm; __u32 entry_1, entry_2, *lp; int error; - struct modify_ldt_ldt_s ldt_info; + struct user_desc ldt_info; error = -EINVAL; @@ -223,34 +204,17 @@ /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { - if (oldmode || - (ldt_info.contents == 0 && - ldt_info.read_exec_only == 1 && - ldt_info.seg_32bit == 0 && - ldt_info.limit_in_pages == 0 && - ldt_info.seg_not_present == 1 && - ldt_info.useable == 0 && - ldt_info.lm == 0)) { + if (oldmode || LDT_empty(&ldt_info)) { entry_1 = 0; entry_2 = 0; goto install; } } - entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) | - (ldt_info.limit & 0x0ffff); - entry_2 = (ldt_info.base_addr & 0xff000000) | - ((ldt_info.base_addr & 0x00ff0000) >> 16) | - (ldt_info.limit & 0xf0000) | - ((ldt_info.read_exec_only ^ 1) << 9) | - (ldt_info.contents << 10) | - ((ldt_info.seg_not_present ^ 1) << 15) | - (ldt_info.seg_32bit << 22) | - (ldt_info.limit_in_pages << 23) | - (ldt_info.lm << 21) | - 0x7000; - if (!oldmode) - entry_2 |= (ldt_info.useable << 20); + entry_1 = LDT_entry_a(&ldt_info); + entry_2 = LDT_entry_b(&ldt_info); + if (oldmode) + entry_2 &= ~(1 << 20); /* Install the new entry ... */ install: diff -Nru a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c --- a/arch/x86_64/kernel/mpparse.c Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/kernel/mpparse.c Tue Oct 15 20:29:15 2002 @@ -10,6 +10,7 @@ * Alan Cox : Added EBDA scanning * Ingo Molnar : various cleanups and rewrites * Maciej W. Rozycki : Bits for default MP configurations + * Paul Diefenbaugh: Added full ACPI support */ #include @@ -21,11 +22,13 @@ #include #include #include +#include #include #include #include #include +#include /* Have we found an MP table */ int smp_found_config; @@ -262,7 +265,7 @@ printk("APIC at: 0x%X\n",mpc->mpc_lapic); /* save the local APIC address, it might be non-default */ - if (!acpi_found_madt) + if (!acpi_lapic) mp_lapic_addr = mpc->mpc_lapic; /* @@ -274,7 +277,7 @@ { struct mpc_config_processor *m= (struct mpc_config_processor *)mpt; - if (!acpi_found_madt) + if (!acpi_lapic) MP_processor_info(m); mpt += sizeof(*m); count += sizeof(*m); @@ -490,19 +493,18 @@ { struct intel_mp_floating *mpf = mpf_found; -#ifdef CONFIG_ACPI_BOOT /* - * Check if the MADT exists, and if so, use it to get processor - * information (ACPI_MADT_LAPIC). The MADT supports the concept - * of both logical (e.g. HT) and physical processor(s); where the - * MPS only supports physical. - */ - if (acpi_boot.madt) { - acpi_found_madt = acpi_table_parse(ACPI_APIC, acpi_parse_madt); - if (acpi_found_madt > 0) - acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); + * ACPI may be used to obtain the entire SMP configuration or just to + * enumerate/configure processors (CONFIG_ACPI_HT_ONLY). Note that + * ACPI supports both logical (e.g. Hyper-Threading) and physical + * processors, where MPS only supports physical. + */ + if (acpi_lapic && acpi_ioapic) { + printk(KERN_INFO "Using ACPI (MADT) for SMP configuration information\n"); + return; } -#endif /*CONFIG_ACPI_BOOT*/ + else if (acpi_lapic) + printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n"); printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { @@ -664,3 +666,315 @@ #endif } + +/* -------------------------------------------------------------------------- + ACPI-based MP Configuration + -------------------------------------------------------------------------- */ + +#ifdef CONFIG_ACPI_BOOT + +void __init mp_register_lapic_address ( + u64 address) +{ + mp_lapic_addr = (unsigned long) address; + + set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); + + if (boot_cpu_id == -1U) + boot_cpu_id = GET_APIC_ID(apic_read(APIC_ID)); + + Dprintk("Boot CPU = %d\n", boot_cpu_physical_apicid); +} + + +void __init mp_register_lapic ( + u8 id, + u8 enabled) +{ + struct mpc_config_processor processor; + int boot_cpu = 0; + + if (id >= MAX_APICS) { + printk(KERN_WARNING "Processor #%d invalid (max %d)\n", + id, MAX_APICS); + return; + } + + if (id == boot_cpu_physical_apicid) + boot_cpu = 1; + + processor.mpc_type = MP_PROCESSOR; + processor.mpc_apicid = id; + processor.mpc_apicver = 0x10; /* TBD: lapic version */ + processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0); + processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0); + processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | + (boot_cpu_data.x86_model << 4) | boot_cpu_data.x86_mask; + processor.mpc_featureflag = boot_cpu_data.x86_capability[0]; + processor.mpc_reserved[0] = 0; + processor.mpc_reserved[1] = 0; + + MP_processor_info(&processor); +} + +#ifdef CONFIG_X86_IO_APIC + +#define MP_ISA_BUS 0 +#define MP_MAX_IOAPIC_PIN 127 + +struct mp_ioapic_routing { + int apic_id; + int irq_start; + int irq_end; + u32 pin_programmed[4]; +} mp_ioapic_routing[MAX_IO_APICS]; + + +static int __init mp_find_ioapic ( + int irq) +{ + int i = 0; + + /* Find the IOAPIC that manages this IRQ. */ + for (i = 0; i < nr_ioapics; i++) { + if ((irq >= mp_ioapic_routing[i].irq_start) + && (irq <= mp_ioapic_routing[i].irq_end)) + return i; + } + + printk(KERN_ERR "ERROR: Unable to locate IOAPIC for IRQ %d/n", irq); + + return -1; +} + + +void __init mp_register_ioapic ( + u8 id, + u32 address, + u32 irq_base) +{ + int idx = 0; + + if (nr_ioapics >= MAX_IO_APICS) { + printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded " + "(found %d)\n", MAX_IO_APICS, nr_ioapics); + panic("Recompile kernel with bigger MAX_IO_APICS!\n"); + } + if (!address) { + printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address" + " found in MADT table, skipping!\n"); + return; + } + + idx = nr_ioapics++; + + mp_ioapics[idx].mpc_type = MP_IOAPIC; + mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE; + mp_ioapics[idx].mpc_apicaddr = address; + + set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); + mp_ioapics[idx].mpc_apicid = io_apic_get_unique_id(idx, id); + mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx); + + /* + * Build basic IRQ lookup table to facilitate irq->io_apic lookups + * and to prevent reprogramming of IOAPIC pins (PCI IRQs). + */ + mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid; + mp_ioapic_routing[idx].irq_start = irq_base; + mp_ioapic_routing[idx].irq_end = irq_base + + io_apic_get_redir_entries(idx); + + printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, " + "IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, + mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, + mp_ioapic_routing[idx].irq_start, + mp_ioapic_routing[idx].irq_end); + + return; +} + + +void __init mp_override_legacy_irq ( + u8 bus_irq, + u8 polarity, + u8 trigger, + u32 global_irq) +{ + struct mpc_config_intsrc intsrc; + int i = 0; + int found = 0; + int ioapic = -1; + int pin = -1; + + /* + * Convert 'global_irq' to 'ioapic.pin'. + */ + ioapic = mp_find_ioapic(global_irq); + if (ioapic < 0) + return; + pin = global_irq - mp_ioapic_routing[ioapic].irq_start; + + /* + * TBD: This check is for faulty timer entries, where the override + * erroneously sets the trigger to level, resulting in a HUGE + * increase of timer interrupts! + */ + if ((bus_irq == 0) && (global_irq == 2) && (trigger == 3)) + trigger = 1; + + intsrc.mpc_type = MP_INTSRC; + intsrc.mpc_irqtype = mp_INT; + intsrc.mpc_irqflag = (trigger << 2) | polarity; + intsrc.mpc_srcbus = MP_ISA_BUS; + intsrc.mpc_srcbusirq = bus_irq; /* IRQ */ + intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; /* APIC ID */ + intsrc.mpc_dstirq = pin; /* INTIN# */ + + Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n", + intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, + (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, + intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq); + + /* + * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it. + * Otherwise create a new entry (e.g. global_irq == 2). + */ + for (i = 0; i < mp_irq_entries; i++) { + if ((mp_irqs[i].mpc_dstapic == intsrc.mpc_dstapic) + && (mp_irqs[i].mpc_dstirq == intsrc.mpc_dstirq)) { + mp_irqs[i] = intsrc; + found = 1; + break; + } + } + if (!found) { + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); + } + + return; +} + + +void __init mp_config_acpi_legacy_irqs (void) +{ + struct mpc_config_intsrc intsrc; + int i = 0; + int ioapic = -1; + + /* + * Fabricate the legacy ISA bus (bus #31). + */ + mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; + Dprintk("Bus #%d is ISA\n", MP_ISA_BUS); + + /* + * Locate the IOAPIC that manages the ISA IRQs (0-15). + */ + ioapic = mp_find_ioapic(0); + if (ioapic < 0) + return; + + intsrc.mpc_type = MP_INTSRC; + intsrc.mpc_irqflag = 0; /* Conforming */ + intsrc.mpc_srcbus = MP_ISA_BUS; + intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; + + /* + * Use the default configuration for the IRQs 0-15. These may be + * overriden by (MADT) interrupt source override entries. + */ + for (i = 0; i < 16; i++) { + + if (i == 2) continue; /* Don't connect IRQ2 */ + + intsrc.mpc_irqtype = i ? mp_INT : mp_ExtINT; /* 8259A to #0 */ + intsrc.mpc_srcbusirq = i; /* Identity mapped */ + intsrc.mpc_dstirq = i; + + Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, " + "%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, + (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, + intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, + intsrc.mpc_dstirq); + + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); + } + + return; +} + +#ifdef CONFIG_ACPI_PCI + +void __init mp_parse_prt (void) +{ + struct list_head *node = NULL; + struct acpi_prt_entry *entry = NULL; + int vector = 0; + int ioapic = -1; + int ioapic_pin = 0; + int irq = 0; + int idx, bit = 0; + + /* + * Parsing through the PCI Interrupt Routing Table (PRT) and program + * routing for all static (IOAPIC-direct) entries. + */ + list_for_each(node, &acpi_prt.entries) { + entry = list_entry(node, struct acpi_prt_entry, node); + + /* We're only interested in static (non-link) entries. */ + if (entry->link.handle) + continue; + + irq = entry->link.index; + ioapic = mp_find_ioapic(irq); + if (ioapic < 0) + continue; + ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; + + /* + * Avoid pin reprogramming. PRTs typically include entries + * with redundant pin->irq mappings (but unique PCI devices); + * we only only program the IOAPIC on the first. + */ + bit = ioapic_pin % 32; + idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32); + if (idx > 3) { + printk(KERN_ERR "Invalid reference to IOAPIC pin " + "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, + ioapic_pin); + continue; + } + if ((1<irq = irq; + continue; + } + + mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<irq = irq; + + printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> vector 0x%02x" + " -> IRQ %d\n", entry->id.segment, entry->id.bus, + entry->id.device, ('A' + entry->pin), + mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, + entry->irq); + } + + return; +} + +#endif /*CONFIG_ACPI_PCI*/ + +#endif /*CONFIG_X86_IO_APIC*/ + +#endif /*CONFIG_ACPI_BOOT*/ diff -Nru a/arch/x86_64/kernel/msr.c b/arch/x86_64/kernel/msr.c --- a/arch/x86_64/kernel/msr.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/kernel/msr.c Tue Oct 15 20:29:12 2002 @@ -247,11 +247,11 @@ * File operations we support */ static struct file_operations msr_fops = { - owner: THIS_MODULE, - llseek: msr_seek, - read: msr_read, - write: msr_write, - open: msr_open, + .owner = THIS_MODULE, + .llseek = msr_seek, + .read = msr_read, + .write = msr_write, + .open = msr_open, }; int __init msr_init(void) diff -Nru a/arch/x86_64/kernel/mtrr.c b/arch/x86_64/kernel/mtrr.c --- a/arch/x86_64/kernel/mtrr.c Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/kernel/mtrr.c Tue Oct 15 20:29:15 2002 @@ -25,6 +25,9 @@ v2.01 June 2002 Dave Jones Removal of redundant abstraction layer. 64-bit fixes. + v2.02 July 2002 Dave Jones + Fix gentry inconsistencies between kernel/userspace. + More casts to clean up warnings. */ #include @@ -50,6 +53,7 @@ #include #include #include +#include #include #include @@ -64,7 +68,7 @@ #include #include -#define MTRR_VERSION "2.01 (20020605)" +#define MTRR_VERSION "2.02 (20020716)" #define TRUE 1 #define FALSE 0 @@ -106,7 +110,7 @@ struct set_mtrr_context { u32 deftype_lo; u32 deftype_hi; - u64 flags; + unsigned long flags; u64 cr4val; }; @@ -117,7 +121,7 @@ u64 cr0; /* Disable interrupts locally */ - local_save_flags(ctxt->flags); + local_irq_save(ctxt->flags); local_irq_disable(); /* Save value of CR4 and clear Page Global Enable (bit 7) */ @@ -221,6 +225,8 @@ u32 size, mtrr_type type, int do_safe) { struct set_mtrr_context ctxt; + u64 base64; + u64 size64; if (do_safe) set_mtrr_prepare (&ctxt); @@ -230,10 +236,12 @@ relevant mask register to disable a range. */ wrmsr (MSR_MTRRphysMask(reg), 0, 0); } else { - wrmsr (MSR_MTRRphysBase(reg), base << PAGE_SHIFT | type, - (base & size_and_mask) >> (32 - PAGE_SHIFT)); - wrmsr (MSR_MTRRphysMask(reg), (-size-1) << PAGE_SHIFT | 0x800, - ((-size-1) & size_and_mask) >> (32 - PAGE_SHIFT)); + base64 = (base << PAGE_SHIFT) & size_and_mask; + wrmsr (MSR_MTRRphysBase(reg), base64 | type, base64 >> 32); + + size64 = ~((size << PAGE_SHIFT) - 1); + size64 = size64 & size_and_mask; + wrmsr (MSR_MTRRphysMask(reg), (u32) (size64 | 0x800), (u32) (size64 >> 32)); } if (do_safe) set_mtrr_done (&ctxt); @@ -267,15 +275,15 @@ int changed = FALSE; rdmsr (MSR_MTRRphysBase(index), lo, hi); - if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) - || (vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) { + if ((vr->base_lo & 0xfffff0ff) != (lo & 0xfffff0ff) || + (vr->base_hi & 0x000fffff) != (hi & 0x000fffff)) { wrmsr (MSR_MTRRphysBase(index), vr->base_lo, vr->base_hi); changed = TRUE; } rdmsr (MSR_MTRRphysMask(index), lo, hi); - if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) - || (vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) { + if ((vr->mask_lo & 0xfffff800) != (lo & 0xfffff800) || + (vr->mask_hi & 0x000fffff) != (hi & 0x000fffff)) { wrmsr (MSR_MTRRphysMask(index), vr->mask_lo, vr->mask_hi); changed = TRUE; } @@ -457,7 +465,7 @@ data.smp_type = type; wait_barrier_execute = TRUE; wait_barrier_cache_enable = TRUE; - atomic_set (&undone_count, smp_num_cpus - 1); + atomic_set (&undone_count, num_online_cpus() - 1); /* Start the ball rolling on other CPUs */ if (smp_call_function (ipi_handler, &data, 1, 0) != 0) @@ -471,7 +479,7 @@ barrier (); /* Set up for completion wait and then release other CPUs to change MTRRs */ - atomic_set (&undone_count, smp_num_cpus - 1); + atomic_set (&undone_count, num_online_cpus() - 1); wait_barrier_execute = FALSE; set_mtrr_up (reg, base, size, type, FALSE); @@ -596,11 +604,22 @@ if (base + size < 0x100) { printk (KERN_WARNING - "mtrr: cannot set region below 1 MiB (0x%lx000,0x%x000)\n", + "mtrr: cannot set region below 1 MiB (0x%Lx000,0x%x000)\n", base, size); return -EINVAL; } +#if defined(__x86_64__) && defined(CONFIG_AGP) +/* { + agp_kern_info info; + if (type != MTRR_TYPE_UNCACHABLE && agp_copy_info(&info) >= 0 && + base<= info.aper_base && + (base<= + info.aper_base+info.aper_size*1024*1024) + printk(KERN_INFO "%s[%d] setting conflicting mtrr into agp aperture\n",current->comm,current->pid); + }*/ +#endif + /* Check upper bits of base and last are equal and lower bits are 0 for base and 1 for last */ last = base + size - 1; @@ -609,7 +628,7 @@ if (lbase != last) { printk (KERN_WARNING - "mtrr: base(0x%lx000) is not aligned on a size(0x%x000) boundary\n", + "mtrr: base(0x%Lx000) is not aligned on a size(0x%x000) boundary\n", base, size); return -EINVAL; } @@ -626,8 +645,14 @@ return -ENOSYS; } - if (base & size_or_mask || size & size_or_mask) { - printk ("mtrr: base or size exceeds the MTRR width\n"); + if (base & (size_or_mask>>PAGE_SHIFT)) { + printk (KERN_WARNING "mtrr: base(%lx) exceeds the MTRR width(%lx)\n", + base, (size_or_mask>>PAGE_SHIFT)); + return -EINVAL; + } + + if (size & (size_or_mask>>PAGE_SHIFT)) { + printk (KERN_WARNING "mtrr: size exceeds the MTRR width\n"); return -EINVAL; } @@ -646,8 +671,8 @@ if ((base < lbase) || (base + size > lbase + lsize)) { up (&mtrr_lock); printk (KERN_WARNING - "mtrr: 0x%lx000,0x%x000 overlaps existing" - " 0x%lx000,0x%x000\n", base, size, lbase, lsize); + "mtrr: 0x%Lx000,0x%x000 overlaps existing" + " 0x%Lx000,0x%x000\n", base, size, lbase, lsize); return -EINVAL; } /* New region is enclosed by an existing region */ @@ -656,7 +681,7 @@ continue; up (&mtrr_lock); printk - ("mtrr: type mismatch for %lx000,%x000 old: %s new: %s\n", + ("mtrr: type mismatch for %Lx000,%x000 old: %s new: %s\n", base, size, attrib_to_str (ltype), attrib_to_str (type)); @@ -720,7 +745,7 @@ { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); + printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); return -EINVAL; } return mtrr_add_page (base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, @@ -763,7 +788,7 @@ } if (reg < 0) { up (&mtrr_lock); - printk ("mtrr: no MTRR for %lx000,%x000 found\n", base, size); + printk ("mtrr: no MTRR for %Lx000,%x000 found\n", base, size); return -EINVAL; } } @@ -814,7 +839,7 @@ { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); + printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); return -EINVAL; } return mtrr_del_page (reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT); @@ -844,7 +869,7 @@ if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); + printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); return -EINVAL; } base >>= PAGE_SHIFT; @@ -869,7 +894,7 @@ if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); + printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); return -EINVAL; } base >>= PAGE_SHIFT; @@ -961,7 +986,7 @@ if ((base & 0xfff) || (size & 0xfff)) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); - printk ("mtrr: size: 0x%x base: 0x%lx\n", size, base); + printk ("mtrr: size: 0x%x base: 0x%Lx\n", size, base); return -EINVAL; } @@ -1007,8 +1032,7 @@ return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; - err = - mtrr_file_add (sentry.base, sentry.size, sentry.type, + err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 0); if (err < 0) return err; @@ -1049,7 +1073,7 @@ return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; - get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type); + get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type); /* Hide entries that go above 4GB */ if (gentry.base + gentry.size > 0x100000 @@ -1070,9 +1094,7 @@ return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; - err = - mtrr_file_add (sentry.base, sentry.size, sentry.type, - file, 1); + err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1); if (err < 0) return err; break; @@ -1112,7 +1134,7 @@ return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; - get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type); + get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type); gentry.type = type; if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) @@ -1131,6 +1153,7 @@ if (fcount == NULL) return 0; + lock_kernel (); max = get_num_var_ranges (); for (i = 0; i < max; ++i) { while (fcount[i] > 0) { @@ -1139,6 +1162,7 @@ --fcount[i]; } } + unlock_kernel (); kfree (fcount); file->private_data = NULL; return 0; @@ -1146,11 +1170,11 @@ static struct file_operations mtrr_fops = { - owner: THIS_MODULE, - read: mtrr_read, - write: mtrr_write, - ioctl: mtrr_ioctl, - release:mtrr_close, + .owner = THIS_MODULE, + .read = mtrr_read, + .write = mtrr_write, + .ioctl = mtrr_ioctl, + .release = mtrr_close, }; #ifdef CONFIG_PROC_FS @@ -1182,10 +1206,9 @@ factor = 'M'; size >>= 20 - PAGE_SHIFT; } - sprintf - (ascii_buffer + ascii_buf_bytes, - "reg%02i: base=0x%05lx000 (%4liMB), size=%4i%cB: %s, count=%d\n", - i, base, base >> (20 - PAGE_SHIFT), size, factor, + sprintf (ascii_buffer + ascii_buf_bytes, + "reg%02i: base=0x%05Lx000 (%4iMB), size=%4i%cB: %s, count=%d\n", + i, base, (u32) base >> (20 - PAGE_SHIFT), size, factor, attrib_to_str (type), usage_table[i]); ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); } @@ -1213,8 +1236,12 @@ if ((cpuid_eax (0x80000000) >= 0x80000008)) { u32 phys_addr; phys_addr = cpuid_eax (0x80000008) & 0xff; - size_or_mask = ~((1 << (phys_addr - PAGE_SHIFT)) - 1); - size_and_mask = ~size_or_mask & 0xfffffffffff00000; + size_or_mask = ~((1L << phys_addr) - 1); + /* + * top bits MBZ as its beyond the addressable range. + * bottom bits MBZ as we don't care about lower 12 bits of addr. + */ + size_and_mask = (~size_or_mask) & 0x000ffffffffff000L; } printk ("mtrr: detected mtrr type: x86-64\n"); } diff -Nru a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c --- a/arch/x86_64/kernel/nmi.c Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/kernel/nmi.c Tue Oct 15 20:29:16 2002 @@ -24,7 +24,7 @@ #include #include -unsigned int nmi_watchdog = NMI_NONE; +unsigned int nmi_watchdog = NMI_LOCAL_APIC; static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ extern void show_registers(struct pt_regs *regs); @@ -43,22 +43,38 @@ #define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79 #define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED +/* Why is there no CPUID flag for this? */ +static __init int cpu_has_lapic(void) +{ + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_INTEL: + case X86_VENDOR_AMD: + return boot_cpu_data.x86 >= 6; + /* .... add more cpus here or find a different way to figure this out. */ + default: + return 0; + } +} + int __init check_nmi_watchdog (void) { int counts[NR_CPUS]; - int j, cpu; + int cpu; + + if (nmi_watchdog == NMI_LOCAL_APIC && !cpu_has_lapic()) { + nmi_watchdog = NMI_NONE; + return -1; + } printk(KERN_INFO "testing NMI watchdog ... "); - for (j = 0; j < NR_CPUS; ++j) { - cpu = cpu_logical_map(j); + for_each_cpu(cpu) { counts[cpu] = cpu_pda[cpu].__nmi_count; } - sti(); + local_irq_enable(); mdelay((10*1000)/nmi_hz); // wait 10 ticks - for (j = 0; j < smp_num_cpus; j++) { - cpu = cpu_logical_map(j); + for_each_cpu(cpu) { if (cpu_pda[cpu].__nmi_count - counts[cpu] <= 5) { printk("CPU#%d: NMI appears to be stuck (%d)!\n", cpu, @@ -84,26 +100,6 @@ if (nmi >= NMI_INVALID) return 0; - if (nmi == NMI_NONE) - nmi_watchdog = nmi; - /* - * If any other x86 CPU has a local APIC, then - * please test the NMI stuff there and send me the - * missing bits. Right now Intel P6 and AMD K7 only. - */ - if ((nmi == NMI_LOCAL_APIC) && - (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && - (boot_cpu_data.x86 == 6)) - nmi_watchdog = nmi; - if ((nmi == NMI_LOCAL_APIC) && - (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && - (boot_cpu_data.x86 == 6)) - nmi_watchdog = nmi; - /* - * We can enable the IO-APIC watchdog - * unconditionally. - */ - if (nmi == NMI_IO_APIC) nmi_watchdog = nmi; return 1; } @@ -167,6 +163,8 @@ int i; unsigned int evntsel; + /* XXX should check these in EFER */ + nmi_perfctr_msr = MSR_K7_PERFCTR0; for(i = 0; i < 4; ++i) { @@ -180,7 +178,7 @@ | K7_NMI_EVENT; wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); - Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); + printk(KERN_INFO "watchdog: setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000)); wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= K7_EVNTSEL_ENABLE; @@ -191,7 +189,11 @@ { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 != 6) + if (boot_cpu_data.x86 < 6) + return; + /* Simics masquerades as AMD, but does not support + performance counters */ + if (strstr(boot_cpu_data.x86_model_id, "Screwdriver")) return; setup_k7_watchdog(); break; @@ -230,7 +232,7 @@ * Just reset the alert counters, (other CPUs might be * spinning on locks we hold): */ - for (i = 0; i < smp_num_cpus; i++) + for (i = 0; i < NR_CPUS; i++) alert_counter[i] = 0; } @@ -243,8 +245,7 @@ * smp_processor_id(). */ int sum, cpu = smp_processor_id(); - - sum = apic_timer_irqs[cpu]; + sum = read_pda(apic_timer_irqs); if (last_irq_sums[cpu] == sum) { /* diff -Nru a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c --- a/arch/x86_64/kernel/pci-dma.c Tue Oct 15 20:29:21 2002 +++ b/arch/x86_64/kernel/pci-dma.c Tue Oct 15 20:29:21 2002 @@ -1,5 +1,5 @@ /* - * Dynamic DMA mapping support. + * Dynamic DMA mapping support. Common code */ #include @@ -8,24 +8,63 @@ #include #include -void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) +dma_addr_t bad_dma_address = -1UL; + +/* Map a set of buffers described by scatterlist in streaming + * mode for DMA. This is the scather-gather version of the + * above pci_map_single interface. Here the scatter gather list + * elements are each tagged with the appropriate dma address + * and length. They are obtained via sg_dma_{address,length}(SG). + * + * NOTE: An implementation may be able to use a smaller number of + * DMA address/length pairs than there are SG table elements. + * (for example via virtual mapping capabilities) + * The routine returns the number of addr/length pairs actually + * used, at most nents. + * + * Device ownership issues as mentioned above for pci_map_single are + * the same here. + */ +int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, + int nents, int direction) { - void *ret; - int gfp = GFP_ATOMIC; + int i; - gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); + BUG_ON(direction == PCI_DMA_NONE); + + /* + * + */ + for (i = 0; i < nents; i++ ) { + struct scatterlist *s = &sg[i]; + if (s->page) { + s->dma_address = pci_map_page(hwdev, s->page, s->offset, + s->length, direction); + } else + BUG(); - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_phys(ret); + if (unlikely(s->dma_address == bad_dma_address)) + goto error; } - return ret; + return nents; + + error: + pci_unmap_sg(hwdev, sg, i, direction); + return 0; } -void pci_free_consistent(struct pci_dev *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) +/* Unmap a set of streaming mode DMA translations. + * Again, cpu read rules concerning calls here are the same as for + * pci_unmap_single() above. + */ +void pci_unmap_sg(struct pci_dev *dev, struct scatterlist *sg, + int nents, int dir) { - free_pages((unsigned long)vaddr, get_order(size)); + int i; + for (i = 0; i < nents; i++) { + struct scatterlist *s = &sg[i]; + BUG_ON(s->page == NULL); + BUG_ON(s->dma_address == 0); + pci_unmap_single(dev, s->dma_address, s->length, dir); + } } diff -Nru a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/kernel/pci-gart.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,560 @@ +/* + * Dynamic DMA mapping support for AMD Hammer. + * + * Use the integrated AGP GART in the Hammer northbridge as an IOMMU for PCI. + * This allows to use PCI devices that only support 32bit addresses on systems + * with more than 4GB. + * + * See Documentation/DMA-mapping.txt for the interface specification. + * + * Copyright 2002 Andi Kleen, SuSE Labs. + * $Id: pci-gart.c,v 1.12 2002/09/19 19:25:32 ak Exp $ + */ + +/* + * Notebook: + +agpgart_be + check if the simple reservation scheme is enough. + +possible future tuning: + fast path for sg streaming mappings + more intelligent flush strategy - flush only a single NB? + move boundary between IOMMU and AGP in GART dynamically + could use exact fit in the gart in alloc_consistent, not order of two. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned long iommu_bus_base; /* GART remapping area (physical) */ +static unsigned long iommu_size; /* size of remapping area bytes */ +static unsigned long iommu_pages; /* .. and in pages */ + +u32 *iommu_gatt_base; /* Remapping table */ + +int no_iommu; +static int no_agp; +int force_mmu = 1; + +extern int fallback_aper_order; +extern int fallback_aper_force; + +/* Allocation bitmap for the remapping area */ +static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED; +static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */ + +#define GPTE_MASK 0xfffffff000 +#define GPTE_VALID 1 +#define GPTE_COHERENT 2 +#define GPTE_ENCODE(x,flag) (((x) & 0xfffffff0) | ((x) >> 28) | GPTE_VALID | (flag)) +#define GPTE_DECODE(x) (((x) & 0xfffff000) | (((x) & 0xff0) << 28)) + +#define for_all_nb(dev) \ + pci_for_each_dev(dev) \ + if (dev->bus->number == 0 && PCI_FUNC(dev->devfn) == 3 && \ + (PCI_SLOT(dev->devfn) >= 24) && (PCI_SLOT(dev->devfn) <= 31)) + +#define EMERGENCY_PAGES 32 /* = 128KB */ + +#ifdef CONFIG_AGP +extern int agp_init(void); +#define AGPEXTERN extern +#else +#define AGPEXTERN +#endif + +/* backdoor interface to AGP driver */ +AGPEXTERN int agp_memory_reserved; +AGPEXTERN __u32 *agp_gatt_table; + +static unsigned long next_bit; /* protected by iommu_bitmap_lock */ + +static unsigned long alloc_iommu(int size) +{ + unsigned long offset, flags; + + spin_lock_irqsave(&iommu_bitmap_lock, flags); + + offset = find_next_zero_string(iommu_gart_bitmap,next_bit,iommu_pages,size); + if (offset == -1) + offset = find_next_zero_string(iommu_gart_bitmap,0,next_bit,size); + if (offset != -1) { + set_bit_string(iommu_gart_bitmap, offset, size); + next_bit = offset+size; + if (next_bit >= iommu_pages) + next_bit = 0; + } + spin_unlock_irqrestore(&iommu_bitmap_lock, flags); + return offset; +} + +static void free_iommu(unsigned long offset, int size) +{ + unsigned long flags; + spin_lock_irqsave(&iommu_bitmap_lock, flags); + clear_bit_string(iommu_gart_bitmap, offset, size); + next_bit = offset; + spin_unlock_irqrestore(&iommu_bitmap_lock, flags); +} + +static inline void flush_gart(void) +{ + struct pci_dev *nb; + for_all_nb(nb) { + u32 flag; + pci_read_config_dword(nb, 0x9c, &flag); /* could cache this */ + /* could complain for PTE walk errors here (bit 1 of flag) */ + flag |= 1; + pci_write_config_dword(nb, 0x9c, flag); + } +} + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *memory; + int gfp = GFP_ATOMIC; + int order, i; + unsigned long iommu_page; + + if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu) + gfp |= GFP_DMA; + + /* + * First try to allocate continuous and use directly if already + * in lowmem. + */ + order = get_order(size); + memory = (void *)__get_free_pages(gfp, order); + if (memory == NULL) { + return NULL; + } else { + int high = (unsigned long)virt_to_bus(memory) + size + >= 0xffffffff; + int mmu = high; + if (force_mmu) + mmu = 1; + if (no_iommu) { + if (high) goto error; + mmu = 0; + } + memset(memory, 0, size); + if (!mmu) { + *dma_handle = virt_to_bus(memory); + return memory; + } + } + + iommu_page = alloc_iommu(1< 0) + atomic_inc(&virt_to_page(mem)->count); + phys_mem = virt_to_phys(mem); + BUG_ON(phys_mem & ~PTE_MASK); + iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem,GPTE_COHERENT); + } + + flush_gart(); + *dma_handle = iommu_bus_base + (iommu_page << PAGE_SHIFT); + return memory; + + error: + free_pages((unsigned long)memory, order); + return NULL; +} + +/* + * Unmap consistent memory. + * The caller must ensure that the device has finished accessing the mapping. + */ +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t bus) +{ + u64 pte; + int order = get_order(size); + unsigned long iommu_page; + int i; + + if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { + free_pages((unsigned long)vaddr, order); + return; + } + iommu_page = (bus - iommu_bus_base) / PAGE_SIZE; + for (i = 0; i < 1<name : "?", dev ? dev->slot_name : "?"); + + if (size > PAGE_SIZE*EMERGENCY_PAGES) { + if (dir == PCI_DMA_FROMDEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic("PCI-DMA: Memory will be corrupted\n"); + if (dir == PCI_DMA_TODEVICE || dir == PCI_DMA_BIDIRECTIONAL) + panic("PCI-DMA: Random memory will be DMAed\n"); + } + +#ifdef CONFIG_IOMMU_LEAK + dump_leak(); +#endif +} + +static inline int need_iommu(struct pci_dev *dev, unsigned long addr, size_t size) +{ + u64 mask = dev ? dev->dma_mask : 0xffffffff; + int high = (~mask & (unsigned long)(addr + size)) != 0; + int mmu = high; + if (force_mmu) + mmu = 1; + if (no_iommu) { + if (high) + panic("pci_map_single: high address but no IOMMU.\n"); + mmu = 0; + } + return mmu; +} + +dma_addr_t pci_map_single(struct pci_dev *dev, void *addr, size_t size,int dir) +{ + unsigned long iommu_page; + unsigned long phys_mem, bus; + int i, npages; + + BUG_ON(dir == PCI_DMA_NONE); + + phys_mem = virt_to_phys(addr); + if (!need_iommu(dev, phys_mem, size)) + return phys_mem; + + npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT; + + iommu_page = alloc_iommu(npages); + if (iommu_page == -1) { + iommu_full(dev, addr, size, dir); + return iommu_bus_base; + } + + phys_mem &= PAGE_MASK; + for (i = 0; i < npages; i++, phys_mem += PAGE_SIZE) { + BUG_ON(phys_mem & ~PTE_MASK); + + /* + * Set coherent mapping here to avoid needing to flush + * the caches on mapping. + */ + iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem, GPTE_COHERENT); + +#ifdef CONFIG_IOMMU_LEAK + /* XXX need eventually caller of pci_map_sg */ + if (iommu_leak_tab) + iommu_leak_tab[iommu_page + i] = __builtin_return_address(0); +#endif + } + flush_gart(); + + bus = iommu_bus_base + iommu_page*PAGE_SIZE; + return bus + ((unsigned long)addr & ~PAGE_MASK); +} + +/* + * Free a temporary PCI mapping. + */ +void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, + size_t size, int direction) +{ + unsigned long iommu_page; + int i, npages; + if (dma_addr < iommu_bus_base + EMERGENCY_PAGES*PAGE_SIZE || + dma_addr > iommu_bus_base + iommu_size) + return; + iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT; + npages = round_up(size, PAGE_SIZE) >> PAGE_SHIFT; + for (i = 0; i < npages; i++) { + iommu_gatt_base[iommu_page + i] = 0; +#ifdef CONFIG_IOMMU_LEAK + if (iommu_leak_tab) + iommu_leak_tab[iommu_page + i] = 0; +#endif + } + flush_gart(); + free_iommu(iommu_page, npages); +} + +EXPORT_SYMBOL(pci_map_single); +EXPORT_SYMBOL(pci_unmap_single); + +static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size) +{ + unsigned long a; + if (!iommu_size) { + iommu_size = aper_size; + if (!no_agp) + iommu_size /= 2; + } + + a = aper + iommu_size; + iommu_size -= round_up(a, LARGE_PAGE_SIZE) - a; + + if (iommu_size < 64*1024*1024) + printk(KERN_WARNING + "PCI-DMA: Warning: Small IOMMU %luMB. Consider increasing the AGP aperture in BIOS\n",iommu_size>>20); + + return iommu_size; +} + +static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) +{ + unsigned aper_size = 0, aper_base_32; + u64 aper_base; + unsigned aper_order; + + pci_read_config_dword(dev, 0x94, &aper_base_32); + pci_read_config_dword(dev, 0x90, &aper_order); + aper_order = (aper_order >> 1) & 7; + + aper_base = aper_base_32 & 0x7fff; + aper_base <<= 25; + + aper_size = (32 * 1024 * 1024) << aper_order; + if (aper_base + aper_size >= 0xffffffff || !aper_size) + aper_base = 0; + + *size = aper_size; + return aper_base; +} + +/* + * Private Northbridge GATT initialization in case we cannot use the + * AGP driver for some reason. + */ +static __init int init_k8_gatt(agp_kern_info *info) +{ + struct pci_dev *dev; + void *gatt; + unsigned aper_base, new_aper_base; + unsigned aper_size, gatt_size, new_aper_size; + + aper_size = aper_base = info->aper_size = 0; + for_all_nb(dev) { + new_aper_base = read_aperture(dev, &new_aper_size); + if (!new_aper_base) + goto nommu; + + if (!aper_base) { + aper_size = new_aper_size; + aper_base = new_aper_base; + } + if (aper_size != new_aper_size || aper_base != new_aper_base) + goto nommu; + } + if (!aper_base) + goto nommu; + info->aper_base = aper_base; + info->aper_size = aper_size>>20; + + gatt_size = (aper_size >> PAGE_SHIFT) * sizeof(u32); + gatt = (void *)__get_free_pages(GFP_KERNEL, get_order(gatt_size)); + if (!gatt) + panic("Cannot allocate GATT table"); + memset(gatt, 0, gatt_size); + change_page_attr(virt_to_page(gatt), gatt_size/PAGE_SIZE, PAGE_KERNEL_NOCACHE); + agp_gatt_table = gatt; + + for_all_nb(dev) { + u32 ctl; + u32 gatt_reg; + + gatt_reg = ((u64)gatt) >> 12; + gatt_reg <<= 4; + pci_write_config_dword(dev, 0x98, gatt_reg); + pci_read_config_dword(dev, 0x90, &ctl); + + ctl |= 1; + ctl &= ~((1<<4) | (1<<5)); + + pci_write_config_dword(dev, 0x90, ctl); + } + flush_gart(); + + + printk("PCI-DMA: aperture base @ %x size %u KB\n", aper_base, aper_size>>10); + return 0; + + nommu: + /* XXX: reject 0xffffffff mask now in pci mapping functions */ + printk(KERN_ERR "PCI-DMA: More than 4GB of RAM and no IOMMU\n" + KERN_ERR "PCI-DMA: 32bit PCI IO may malfunction."); + return -1; +} + +void __init pci_iommu_init(void) +{ + agp_kern_info info; + unsigned long aper_size; + unsigned long iommu_start; + +#ifndef CONFIG_AGP + no_agp = 1; +#else + no_agp = no_agp || (agp_init() < 0) || (agp_copy_info(&info) < 0); +#endif + + if (no_iommu || (!force_mmu && end_pfn < 0xffffffff>>PAGE_SHIFT)) { + printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); + no_iommu = 1; + return; + } + + if (no_agp) { + int err = -1; + printk(KERN_INFO "PCI-DMA: Disabling AGP.\n"); + no_agp = 1; + if (force_mmu || end_pfn >= 0xffffffff>>PAGE_SHIFT) + err = init_k8_gatt(&info); + if (err < 0) { + printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n"); + no_iommu = 1; + return; + } + } + + aper_size = info.aper_size * 1024 * 1024; + iommu_size = check_iommu_size(info.aper_base, aper_size); + iommu_pages = iommu_size >> PAGE_SHIFT; + + iommu_gart_bitmap = (void*)__get_free_pages(GFP_KERNEL, + get_order(iommu_pages/8)); + if (!iommu_gart_bitmap) + panic("Cannot allocate iommu bitmap\n"); + memset(iommu_gart_bitmap, 0, iommu_pages/8); + +#ifdef CONFIG_IOMMU_LEAK + if (leak_trace) { + iommu_leak_tab = (void *)__get_free_pages(GFP_KERNEL, + get_order(iommu_pages*sizeof(void *))); + if (iommu_leak_tab) + memset(iommu_leak_tab, 0, iommu_pages * 8); + else + printk("PCI-DMA: Cannot allocate leak trace area\n"); + } +#endif + + /* + * Out of IOMMU space handling. + * Reserve some invalid pages at the beginning of the GART. + */ + set_bit_string(iommu_gart_bitmap, 0, EMERGENCY_PAGES); + + agp_memory_reserved = iommu_size; + printk(KERN_INFO"PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", + iommu_size>>20); + + iommu_start = aper_size - iommu_size; + iommu_bus_base = info.aper_base + iommu_start; + iommu_gatt_base = agp_gatt_table + (iommu_start>>PAGE_SHIFT); + bad_dma_address = iommu_bus_base; + + asm volatile("wbinvd" ::: "memory"); +} + +/* iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]] + size set size of iommu (in bytes) + noagp don't initialize the AGP driver and use full aperture. + off don't use the IOMMU + leak turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on) + memaper[=order] allocate an own aperture over RAM with size 32MB^order. +*/ +__init int iommu_setup(char *opt) +{ + int arg; + char *p = opt; + + for (;;) { + if (!memcmp(p,"noagp", 5)) + no_agp = 1; + if (!memcmp(p,"off", 3)) + no_iommu = 1; + if (!memcmp(p,"force", 5)) + force_mmu = 1; + if (!memcmp(p,"noforce", 7)) + force_mmu = 0; + if (!memcmp(p, "memaper", 7)) { + fallback_aper_force = 1; + p += 7; + if (*p == '=' && get_option(&p, &arg)) + fallback_aper_order = arg; + } +#ifdef CONFIG_IOMMU_LEAK + if (!memcmp(p,"leak", 4)) + leak_trace = 1; +#endif + if (isdigit(*p) && get_option(&p, &arg)) + iommu_size = arg; + do { + if (*p == ' ' || *p == 0) + return 0; + } while (*p++ != ','); + } + return 1; +} + diff -Nru a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/kernel/pci-nommu.c Tue Oct 15 20:29:23 2002 @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +/* + * Dummy IO MMU functions + */ + +extern unsigned long end_pfn; + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + if (hwdev == NULL || + end_pfn > (hwdev->dma_mask>>PAGE_SHIFT) || /* XXX */ + (u32)hwdev->dma_mask < 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + memset(ret, 0, size); + *dma_handle = virt_to_bus(ret); + } + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + free_pages((unsigned long)vaddr, get_order(size)); +} + + +static void __init check_ram(void) +{ + if (end_pfn >= 0xffffffff>>PAGE_SHIFT) { + printk(KERN_ERR "WARNING more than 4GB of memory but no IOMMU.\n" + KERN_ERR "WARNING 32bit PCI may malfunction.\n"); + /* Could play with highmem_start_page here to trick some subsystems + into bounce buffers. Unfortunately that would require setting + CONFIG_HIGHMEM too. + */ + } +} diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c --- a/arch/x86_64/kernel/process.c Tue Oct 15 20:29:11 2002 +++ b/arch/x86_64/kernel/process.c Tue Oct 15 20:29:11 2002 @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -57,6 +56,7 @@ #include asmlinkage extern void ret_from_fork(void); +int sys_arch_prctl(int code, unsigned long addr); unsigned long kernel_thread_flags = CLONE_VM; @@ -67,11 +67,6 @@ */ void (*pm_idle)(void); -/* - * Power off function, if any - */ -void (*pm_power_off)(void); - void disable_hlt(void) { hlt_counter++; @@ -160,123 +155,6 @@ __setup("idle=", idle_setup); -static long no_idt[3]; -static int reboot_mode; - -#ifdef CONFIG_SMP -int reboot_smp = 0; -static int reboot_cpu = -1; -#endif -static int __init reboot_setup(char *str) -{ - while(1) { - switch (*str) { - case 'w': /* "warm" reboot (no memory testing etc) */ - reboot_mode = 0x1234; - break; - case 'c': /* "cold" reboot (with memory testing etc) */ - reboot_mode = 0x0; - break; -#ifdef CONFIG_SMP - case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ - reboot_smp = 1; - if (isdigit(str[1])) - sscanf(str+1, "%d", &reboot_cpu); - else if (!strncmp(str,"smp",3)) - sscanf(str+3, "%d", &reboot_cpu); - /* 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 */ - break; -#endif - } - if((str = strchr(str,',')) != NULL) - str++; - else - break; - } - return 1; -} - -__setup("reboot=", reboot_setup); - -static inline void kb_wait(void) -{ - int i; - - for (i=0; i<0x10000; i++) - if ((inb_p(0x64) & 0x02) == 0) - break; -} - -void machine_restart(char * __unused) -{ -#if CONFIG_SMP - int cpuid; - - cpuid = GET_APIC_ID(apic_read(APIC_ID)); - - if (reboot_smp) { - - /* check to see if reboot_cpu is valid - if its not, default to the BSP */ - if ((reboot_cpu == -1) || - (reboot_cpu > (NR_CPUS -1)) || - !(phys_cpu_present_map & (1<pid, current->comm, print_tainted()); - printk("RIP: %04lx:[<%016lx>]\n", regs->cs & 0xffff, regs->rip); - printk("RSP: %016lx EFLAGS: %08lx\n", regs->rsp, regs->eflags); + printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip); + printk_address(regs->rip); + printk("\nRSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags); printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", regs->rax, regs->rbx, regs->rcx); printk("RDX: %016lx RSI: %016lx RDI: %016lx\n", @@ -378,6 +258,7 @@ if (rsp == ~0) { childregs->rsp = (unsigned long)childregs; } + p->user_tid = NULL; p->thread.rsp = (unsigned long) childregs; p->thread.rsp0 = (unsigned long) (childregs+1); @@ -404,6 +285,30 @@ (IO_BITMAP_SIZE+1)*4); } + /* + * Set a new TLS for the child thread? + */ + if (clone_flags & CLONE_SETTLS) { + struct n_desc_struct *desc; + struct user_desc info; + int idx; + + if (copy_from_user(&info, test_thread_flag(TIF_IA32) ? + (void *)childregs->rsi : + (void *)childregs->rdx, sizeof(info))) + return -EFAULT; + if (LDT_empty(&info)) + return -EINVAL; + + idx = info.entry_number; + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = (struct n_desc_struct *)(p->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN; + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + } + return 0; } @@ -428,8 +333,8 @@ { struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; - struct tss_struct *tss = init_tss + smp_processor_id(); - + int cpu = smp_processor_id(); + struct tss_struct *tss = init_tss + cpu; unlazy_fpu(prev_p); @@ -440,6 +345,7 @@ /* * Switch DS and ES. + * This won't pick up thread selector changes, but I guess that is ok. */ asm volatile("movl %%es,%0" : "=m" (prev->es)); if (unlikely(next->es | prev->es)) @@ -452,25 +358,38 @@ /* * Switch FS and GS. * XXX Check if this is safe on SMP (!= -> |) + * Need to simplify this. */ { unsigned int fsindex; + unsigned int gsindex; asm volatile("movl %%fs,%0" : "=g" (fsindex)); - if (unlikely(fsindex != next->fsindex)) /* or likely? */ - loadsegment(fs, next->fsindex); + asm volatile("movl %%gs,%0" : "=g" (gsindex)); + + /* + * Load the per-thread Thread-Local Storage descriptor. + */ + if (load_TLS(next, cpu)) { + loadsegment(fs,next->fsindex); + /* should find a way to optimize this away - it is + slow */ + goto loadgs; + } else { + if (fsindex != next->fsindex) + loadsegment(fs,next->fsindex); + if (gsindex != next->gsindex) { + loadgs: + load_gs_index(next->gsindex); + } + } + if (unlikely(fsindex != prev->fsindex)) prev->fs = 0; if ((fsindex != prev->fsindex) || (prev->fs != next->fs)) wrmsrl(MSR_FS_BASE, next->fs); prev->fsindex = fsindex; - } - { - unsigned int gsindex; - asm volatile("movl %%gs,%0" : "=g" (gsindex)); - if (unlikely(gsindex != next->gsindex)) - load_gs_index(next->gs); if (unlikely(gsindex != prev->gsindex)) prev->gs = 0; if (gsindex != prev->gsindex || prev->gs != next->gs) @@ -486,6 +405,7 @@ write_pda(pcurrent, next_p); write_pda(kernelstack, (unsigned long)next_p->thread_info + THREAD_SIZE - PDA_STACKOFFSET); + /* * Now maybe reload the debug registers */ @@ -556,16 +476,16 @@ asmlinkage long sys_fork(struct pt_regs regs) { struct task_struct *p; - p = do_fork(SIGCHLD, regs.rsp, ®s, 0); + p = do_fork(SIGCHLD, regs.rsp, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } -asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs regs) +asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp, void *user_tid, struct pt_regs regs) { struct task_struct *p; if (!newsp) newsp = regs.rsp; - p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0); + p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0, user_tid); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -582,7 +502,7 @@ asmlinkage long sys_vfork(struct pt_regs regs) { struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, ®s, 0); + p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.rsp, ®s, 0, NULL); return IS_ERR(p) ? PTR_ERR(p) : p->pid; } @@ -617,7 +537,7 @@ #undef last_sched #undef first_sched -asmlinkage int sys_arch_prctl(int code, unsigned long addr) +int sys_arch_prctl(int code, unsigned long addr) { int ret = 0; unsigned long tmp; @@ -658,3 +578,115 @@ return ret; } +/* + * sys_alloc_thread_area: get a yet unused TLS descriptor index. + */ +static int get_free_idx(void) +{ + struct thread_struct *t = ¤t->thread; + int idx; + + for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++) + if (desc_empty((struct n_desc_struct *)(t->tls_array) + idx)) + return idx + GDT_ENTRY_TLS_MIN; + return -ESRCH; +} + +/* + * Set a given TLS descriptor: + * When you want addresses > 32bit use arch_prctl() + */ +asmlinkage int sys_set_thread_area(struct user_desc *u_info) +{ + struct thread_struct *t = ¤t->thread; + struct user_desc info; + struct n_desc_struct *desc; + int cpu, idx; + + if (copy_from_user(&info, u_info, sizeof(info))) + return -EFAULT; + idx = info.entry_number; + + /* + * index -1 means the kernel should try to find and + * allocate an empty descriptor: + */ + if (idx == -1) { + idx = get_free_idx(); + if (idx < 0) + return idx; + if (put_user(idx, &u_info->entry_number)) + return -EFAULT; + } + + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = ((struct n_desc_struct *)t->tls_array) + idx - GDT_ENTRY_TLS_MIN; + + /* + * We must not get preempted while modifying the TLS. + */ + cpu = get_cpu(); + + if (LDT_empty(&info)) { + desc->a = 0; + desc->b = 0; + } else { + desc->a = LDT_entry_a(&info); + desc->b = LDT_entry_b(&info); + } + load_TLS(t, cpu); + + put_cpu(); + return 0; +} + +/* + * Get the current Thread-Local Storage area: + */ + +#define GET_BASE(desc) ( \ + (((desc)->a >> 16) & 0x0000ffff) | \ + (((desc)->b << 16) & 0x00ff0000) | \ + ( (desc)->b & 0xff000000) ) + +#define GET_LIMIT(desc) ( \ + ((desc)->a & 0x0ffff) | \ + ((desc)->b & 0xf0000) ) + +#define GET_32BIT(desc) (((desc)->b >> 23) & 1) +#define GET_CONTENTS(desc) (((desc)->b >> 10) & 3) +#define GET_WRITABLE(desc) (((desc)->b >> 9) & 1) +#define GET_LIMIT_PAGES(desc) (((desc)->b >> 23) & 1) +#define GET_PRESENT(desc) (((desc)->b >> 15) & 1) +#define GET_USEABLE(desc) (((desc)->b >> 20) & 1) + +asmlinkage int sys_get_thread_area(struct user_desc *u_info) +{ + struct user_desc info; + struct n_desc_struct *desc; + int idx; + + if (get_user(idx, &u_info->entry_number)) + return -EFAULT; + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + + desc = ((struct n_desc_struct *)current->thread.tls_array) + idx - GDT_ENTRY_TLS_MIN; + + memset(&info, 0, sizeof(struct user_desc)); + info.entry_number = idx; + info.base_addr = GET_BASE(desc); + info.limit = GET_LIMIT(desc); + info.seg_32bit = GET_32BIT(desc); + info.contents = GET_CONTENTS(desc); + info.read_exec_only = !GET_WRITABLE(desc); + info.limit_in_pages = GET_LIMIT_PAGES(desc); + info.seg_not_present = !GET_PRESENT(desc); + info.useable = GET_USEABLE(desc); + + if (copy_to_user(u_info, &info, sizeof(info))) + return -EFAULT; + return 0; +} diff -Nru a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c --- a/arch/x86_64/kernel/ptrace.c Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/kernel/ptrace.c Tue Oct 15 20:29:15 2002 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,11 @@ return -EIO; child->thread.es = value & 0xffff; return 0; + case offsetof(struct user_regs_struct,ss): + if ((value & 3) != 3) + return -EIO; + value &= 0xffff; + return 0; case offsetof(struct user_regs_struct,fs_base): if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) return -EIO; @@ -128,7 +134,7 @@ value |= tmp; break; case offsetof(struct user_regs_struct,cs): - if (value && (value & 3) != 3) + if ((value & 3) != 3) return -EIO; value &= 0xffff; break; @@ -171,6 +177,9 @@ if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) + goto out; + ret = security_ops->ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff -Nru a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/kernel/reboot.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,136 @@ +/* Various gunk just to reboot the machine. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Power off function, if any + */ +void (*pm_power_off)(void); + +static long no_idt[3]; +static int reboot_mode; + +#ifdef CONFIG_SMP +int reboot_smp = 0; +static int reboot_cpu = -1; +#endif + +static int __init reboot_setup(char *str) +{ + while(1) { + switch (*str) { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; +#ifdef CONFIG_SMP + case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ + reboot_smp = 1; + if (isdigit(str[1])) + sscanf(str+1, "%d", &reboot_cpu); + else if (!strncmp(str,"smp",3)) + sscanf(str+3, "%d", &reboot_cpu); + /* 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 */ + break; +#endif + } + if((str = strchr(str,',')) != NULL) + str++; + else + break; + } + return 1; +} + +__setup("reboot=", reboot_setup); + +static inline void kb_wait(void) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +void machine_restart(char * __unused) +{ +#if CONFIG_SMP + int cpuid; + + cpuid = GET_APIC_ID(apic_read(APIC_ID)); + + if (reboot_smp) { + + /* check to see if reboot_cpu is valid + if its not, default to the BSP */ + if ((reboot_cpu == -1) || + (reboot_cpu > (NR_CPUS -1)) || + !(phys_cpu_present_map & (1<wait); } -static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; - void __down(struct semaphore * sem) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + tsk->state = TASK_UNINTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); - spin_lock_irq(&semaphore_lock); sem->sleepers++; for (;;) { int sleepers = sem->sleepers; /* * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. + * playing, because we own the spinlock in + * the wait_queue_head. */ if (!atomic_add_negative(sleepers - 1, &sem->count)) { sem->sleepers = 0; break; } sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); + spin_unlock_irqrestore(&sem->wait.lock, flags); schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); tsk->state = TASK_UNINTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); } - spin_unlock_irq(&semaphore_lock); - remove_wait_queue(&sem->wait, &wait); + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); tsk->state = TASK_RUNNING; - wake_up(&sem->wait); } int __down_interruptible(struct semaphore * sem) @@ -94,11 +96,13 @@ int retval = 0; struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); + unsigned long flags; + tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue_exclusive(&sem->wait, &wait); + spin_lock_irqsave(&sem->wait.lock, flags); + add_wait_queue_exclusive_locked(&sem->wait, &wait); - spin_lock_irq(&semaphore_lock); - sem->sleepers ++; + sem->sleepers++; for (;;) { int sleepers = sem->sleepers; @@ -118,25 +122,27 @@ /* * Add "everybody else" into it. They aren't - * playing, because we own the spinlock. The - * "-1" is because we're still hoping to get - * the lock. + * playing, because we own the spinlock in + * wait_queue_head. The "-1" is because we're + * still hoping to get the semaphore. */ if (!atomic_add_negative(sleepers - 1, &sem->count)) { sem->sleepers = 0; break; } sem->sleepers = 1; /* us - see -1 above */ - spin_unlock_irq(&semaphore_lock); + spin_unlock_irqrestore(&sem->wait.lock, flags); schedule(); + + spin_lock_irqsave(&sem->wait.lock, flags); tsk->state = TASK_INTERRUPTIBLE; - spin_lock_irq(&semaphore_lock); } - spin_unlock_irq(&semaphore_lock); + remove_wait_queue_locked(&sem->wait, &wait); + wake_up_locked(&sem->wait); + spin_unlock_irqrestore(&sem->wait.lock, flags); + tsk->state = TASK_RUNNING; - remove_wait_queue(&sem->wait, &wait); - wake_up(&sem->wait); return retval; } @@ -153,18 +159,20 @@ int sleepers; unsigned long flags; - spin_lock_irqsave(&semaphore_lock, flags); + spin_lock_irqsave(&sem->wait.lock, flags); sleepers = sem->sleepers + 1; sem->sleepers = 0; /* * Add "everybody else" and us into it. They aren't - * playing, because we own the spinlock. + * playing, because we own the spinlock in the + * wait_queue_head. */ - if (!atomic_add_negative(sleepers, &sem->count)) - wake_up(&sem->wait); + if (!atomic_add_negative(sleepers, &sem->count)) { + wake_up_locked(&sem->wait); + } - spin_unlock_irqrestore(&semaphore_lock, flags); + spin_unlock_irqrestore(&sem->wait.lock, flags); return 1; } diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c --- a/arch/x86_64/kernel/setup.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/kernel/setup.c Tue Oct 15 20:29:12 2002 @@ -50,18 +50,18 @@ #include #include #include +#include /* * Machine setup.. */ -extern void mcheck_init(struct cpuinfo_x86 *c); -extern void init_memory_mapping(void); - -struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; +struct cpuinfo_x86 boot_cpu_data; unsigned long mmu_cr4_features; +int acpi_disabled __initdata = 0; + /* For PCI or other memory-mapped resources */ unsigned long pci_mem_start = 0x10000000; @@ -86,8 +86,8 @@ static int disable_x86_fxsr __initdata = 0; -static char command_line[COMMAND_LINE_SIZE]; - char saved_command_line[COMMAND_LINE_SIZE]; +char command_line[COMMAND_LINE_SIZE]; +char saved_command_line[COMMAND_LINE_SIZE]; struct resource standard_io_resources[] = { { "dma1", 0x00, 0x1f, IORESOURCE_BUSY }, @@ -102,9 +102,9 @@ #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource)) -static struct resource code_resource = { "Kernel code", 0x100000, 0 }; -static struct resource data_resource = { "Kernel data", 0, 0 }; -static struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY }; +struct resource code_resource = { "Kernel code", 0x100000, 0 }; +struct resource data_resource = { "Kernel data", 0, 0 }; +struct resource vram_resource = { "Video RAM area", 0xa0000, 0xbffff, IORESOURCE_BUSY }; /* System ROM resources */ #define MAXROMS 6 @@ -178,358 +178,33 @@ } } -void __init add_memory_region(unsigned long long start, - unsigned long long size, int type) -{ - int x = e820.nr_map; - - if (x == E820MAX) { - printk(KERN_ERR "Ooops! Too many entries in the memory map!\n"); - return; - } - - e820.map[x].addr = start; - e820.map[x].size = size; - e820.map[x].type = type; - e820.nr_map++; -} /* add_memory_region */ - -#define E820_DEBUG 1 - -static void __init print_memory_map(char *who) -{ - int i; - - for (i = 0; i < e820.nr_map; i++) { - printk(" %s: %016Lx - %016Lx ", who, - (unsigned long long) e820.map[i].addr, - (unsigned long long) (e820.map[i].addr + e820.map[i].size)); - switch (e820.map[i].type) { - case E820_RAM: printk("(usable)\n"); - break; - case E820_RESERVED: - printk("(reserved)\n"); - break; - case E820_ACPI: - printk("(ACPI data)\n"); - break; - case E820_NVS: - printk("(ACPI NVS)\n"); - break; - default: printk("type %u\n", e820.map[i].type); - break; - } - } -} - -/* - * Sanitize the BIOS e820 map. - * - * Some e820 responses include overlapping entries. The following - * replaces the original e820 map with a new one, removing overlaps. - * - */ -static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map) -{ - struct change_member { - struct e820entry *pbios; /* pointer to original bios entry */ - unsigned long long addr; /* address for this change point */ - }; - struct change_member change_point_list[2*E820MAX]; - struct change_member *change_point[2*E820MAX]; - struct e820entry *overlap_list[E820MAX]; - struct e820entry new_bios[E820MAX]; - struct change_member *change_tmp; - unsigned long current_type, last_type; - unsigned long long last_addr; - int chgidx, still_changing; - int overlap_entries; - int new_bios_entry; - int old_nr, new_nr; - int i; - - /* - Visually we're performing the following (1,2,3,4 = memory types)... - - Sample memory map (w/overlaps): - ____22__________________ - ______________________4_ - ____1111________________ - _44_____________________ - 11111111________________ - ____________________33__ - ___________44___________ - __________33333_________ - ______________22________ - ___________________2222_ - _________111111111______ - _____________________11_ - _________________4______ - - Sanitized equivalent (no overlap): - 1_______________________ - _44_____________________ - ___1____________________ - ____22__________________ - ______11________________ - _________1______________ - __________3_____________ - ___________44___________ - _____________33_________ - _______________2________ - ________________1_______ - _________________4______ - ___________________2____ - ____________________33__ - ______________________4_ - */ - - /* if there's only one memory region, don't bother */ - if (*pnr_map < 2) - return -1; - - old_nr = *pnr_map; - - /* bail out if we find any unreasonable addresses in bios map */ - for (i=0; iaddr = biosmap[i].addr; - change_point[chgidx++]->pbios = &biosmap[i]; - change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size; - change_point[chgidx++]->pbios = &biosmap[i]; - } - - /* sort change-point list by memory addresses (low -> high) */ - still_changing = 1; - while (still_changing) { - still_changing = 0; - for (i=1; i < 2*old_nr; i++) { - /* if > , swap */ - /* or, if current= & last=, swap */ - if ((change_point[i]->addr < change_point[i-1]->addr) || - ((change_point[i]->addr == change_point[i-1]->addr) && - (change_point[i]->addr == change_point[i]->pbios->addr) && - (change_point[i-1]->addr != change_point[i-1]->pbios->addr)) - ) - { - change_tmp = change_point[i]; - change_point[i] = change_point[i-1]; - change_point[i-1] = change_tmp; - still_changing=1; - } - } - } - - /* create a new bios memory map, removing overlaps */ - overlap_entries=0; /* number of entries in the overlap table */ - new_bios_entry=0; /* index for creating new bios map entries */ - last_type = 0; /* start with undefined memory type */ - last_addr = 0; /* start with 0 as last starting address */ - /* loop through change-points, determining affect on the new bios map */ - for (chgidx=0; chgidx < 2*old_nr; chgidx++) - { - /* keep track of all overlapping bios entries */ - if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr) - { - /* add map entry to overlap list (> 1 entry implies an overlap) */ - overlap_list[overlap_entries++]=change_point[chgidx]->pbios; - } - else - { - /* remove entry from list (order independent, so swap with last) */ - for (i=0; ipbios) - overlap_list[i] = overlap_list[overlap_entries-1]; - } - overlap_entries--; - } - /* if there are overlapping entries, decide which "type" to use */ - /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */ - current_type = 0; - for (i=0; itype > current_type) - current_type = overlap_list[i]->type; - /* continue building up new bios map based on this information */ - if (current_type != last_type) { - if (last_type != 0) { - new_bios[new_bios_entry].size = - change_point[chgidx]->addr - last_addr; - /* move forward only if the new size was non-zero */ - if (new_bios[new_bios_entry].size != 0) - if (++new_bios_entry >= E820MAX) - break; /* no more space left for new bios entries */ - } - if (current_type != 0) { - new_bios[new_bios_entry].addr = change_point[chgidx]->addr; - new_bios[new_bios_entry].type = current_type; - last_addr=change_point[chgidx]->addr; - } - last_type = current_type; - } - } - new_nr = new_bios_entry; /* retain count for new bios entries */ - - /* copy new bios mapping into original location */ - memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry)); - *pnr_map = new_nr; - - return 0; -} - -/* - * Copy the BIOS e820 map into a safe place. - * - * Sanity-check it while we're at it.. - * - * If we're lucky and live on a modern system, the setup code - * will have given us a memory map that we can use to properly - * set up memory. If we aren't, we'll fake a memory map. - * - * We check to see that the memory map contains at least 2 elements - * before we'll use it, because the detection code in setup.S may - * not be perfect and most every PC known to man has two memory - * regions: one from 0 to 640k, and one from 1mb up. (The IBM - * thinkpad 560x, for example, does not cooperate with the memory - * detection code.) - */ -static int __init copy_e820_map(struct e820entry * biosmap, int nr_map) -{ - /* Only one memory region (or negative)? Ignore it */ - if (nr_map < 2) - return -1; - - do { - unsigned long long start = biosmap->addr; - unsigned long long size = biosmap->size; - unsigned long long end = start + size; - unsigned long type = biosmap->type; - - /* Overflow in 64 bits? Ignore the memory map. */ - if (start > end) - return -1; - - /* - * Some BIOSes claim RAM in the 640k - 1M region. - * Not right. Fix it up. - */ - if (type == E820_RAM) { - if (start < 0x100000ULL && end > 0xA0000ULL) { - if (start < 0xA0000ULL) - add_memory_region(start, 0xA0000ULL-start, type); - if (end <= 0x100000ULL) - continue; - start = 0x100000ULL; - size = end - start; - } - } - add_memory_region(start, size, type); - } while (biosmap++,--nr_map); - return 0; -} - -/* - * Do NOT EVER look at the BIOS memory size location. - * It does not work on many machines. - */ -#define LOWMEMSIZE() (0x9f000) - -void __init setup_memory_region(void) -{ - char *who = "BIOS-e820"; - - /* - * Try to copy the BIOS-supplied E820-map. - * - * Otherwise fake a memory map; one section from 0k->640k, - * the next section from 1mb->appropriate_mem_k - */ - sanitize_e820_map(E820_MAP, &E820_MAP_NR); - if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { - unsigned long mem_size; - - /* compare results from other methods and take the greater */ - if (ALT_MEM_K < EXT_MEM_K) { - mem_size = EXT_MEM_K; - who = "BIOS-88"; - } else { - mem_size = ALT_MEM_K; - who = "BIOS-e801"; - } - - e820.nr_map = 0; - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); - } - printk(KERN_INFO "BIOS-provided physical RAM map:\n"); - print_memory_map(who); -} /* setup_memory_region */ - - -static inline void parse_mem_cmdline (char ** cmdline_p) +static __init void parse_cmdline_early (char ** cmdline_p) { char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; - int usermem = 0; /* Save unparsed command line copy for /proc/cmdline */ memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; for (;;) { - /* - * "mem=nopentium" disables the 4MB page tables. - * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM - * to , overriding the bios size. - * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from - * to +, overriding the bios size. - */ - if (c == ' ' && !memcmp(from, "mem=", 4)) { - if (to != command_line) - to--; - if (!memcmp(from+4, "nopentium", 9)) { - from += 9+4; - clear_bit(X86_FEATURE_PSE, &boot_cpu_data.x86_capability); - } else if (!memcmp(from+4, "exactmap", 8)) { - from += 8+4; - e820.nr_map = 0; - usermem = 1; - } else { - /* If the user specifies memory size, we - * blow away any automatically generated - * size - */ - unsigned long long start_at, mem_size; + if (c != ' ') + goto next_char; - if (usermem == 0) { - /* first time in: zap the whitelist - * and reinitialize it with the - * standard low-memory region. - */ - e820.nr_map = 0; - usermem = 1; - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - } - mem_size = memparse(from+4, &from); - if (*from == '@') - start_at = memparse(from+1, &from); - else { - start_at = HIGH_MEMORY; - mem_size -= HIGH_MEMORY; - usermem=0; - } - add_memory_region(start_at, mem_size, E820_RAM); - } + /* "acpi=off" disables both ACPI table parsing and interpreter init */ + if (!memcmp(from, "acpi=off", 8)) + acpi_disabled = 1; + + if (!memcmp(from, "mem=", 4)) + parse_memopt(from+4); + +#ifdef CONFIG_GART_IOMMU + if (!memcmp(from,"iommu=",6)) { + iommu_setup(from+6); } +#endif + + next_char: c = *(from++); if (!c) break; @@ -539,15 +214,23 @@ } *to = '\0'; *cmdline_p = command_line; - if (usermem) { - printk(KERN_INFO "user-defined physical RAM map:\n"); - print_memory_map("user"); - } + print_user_map(); } -unsigned long start_pfn, end_pfn; +#ifndef CONFIG_DISCONTIGMEM +static void __init contig_initmem_init(void) +{ + unsigned long bootmap_size, bootmap; + bootmap_size = bootmem_bootmap_pages(end_pfn)<> PAGE_SHIFT, end_pfn); + e820_bootmem_free(&contig_page_data, 0, end_pfn << PAGE_SHIFT); + reserve_bootmem(bootmap, bootmap_size); +} +#endif -extern void exception_table_check(void); void __init setup_arch(char **cmdline_p) { @@ -579,7 +262,7 @@ data_resource.start = virt_to_phys(&_etext); data_resource.end = virt_to_phys(&_edata)-1; - parse_mem_cmdline(cmdline_p); + parse_cmdline_early(cmdline_p); #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) @@ -595,68 +278,12 @@ */ start_pfn = PFN_UP(__pa_symbol(&_end)); - /* - * Find the highest page frame number we have available - */ - end_pfn = 0; - for (i = 0; i < e820.nr_map; i++) { - unsigned long start, end; - /* RAM? */ - if (e820.map[i].type != E820_RAM) - continue; - start = PFN_UP(e820.map[i].addr); - end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); - if (start >= end) - continue; - if (end > end_pfn) - end_pfn = end; - } - - if (end_pfn > MAXMEM_PFN) { - end_pfn = MAXMEM_PFN; - } + e820_end_of_ram(); init_memory_mapping(); - /* - * Initialize the boot-time allocator (with low memory only): - */ - bootmap_size = init_bootmem(start_pfn, end_pfn); - - /* - * Register fully available low RAM pages with the bootmem allocator. - */ - for (i = 0; i < e820.nr_map; i++) { - unsigned long curr_pfn, last_pfn, size; - /* - * Reserve usable low memory - */ - if (e820.map[i].type != E820_RAM) - continue; - /* - * We are rounding up the start address of usable memory: - */ - curr_pfn = PFN_UP(e820.map[i].addr); - if (curr_pfn >= end_pfn) - continue; - /* - * ... and at the end of the usable range downwards: - */ - last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); - - if (last_pfn > end_pfn) - last_pfn = end_pfn; - - /* - * .. finally, did all the rounding and playing - * around just make the area go away? - */ - if (last_pfn <= curr_pfn) - continue; + contig_initmem_init(); - size = last_pfn - curr_pfn; - free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); - } /* * Reserve the bootmem bitmap itself as well. We do this in two * steps (first step was init_bootmem()) because this catches @@ -694,7 +321,7 @@ #endif #ifdef CONFIG_BLK_DEV_INITRD if (LOADER_TYPE && INITRD_START) { - if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) { + if (INITRD_START + INITRD_SIZE <= (end_pfn << PAGE_SHIFT)) { reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = INITRD_START ? INITRD_START + PAGE_OFFSET : 0; @@ -704,7 +331,7 @@ printk(KERN_ERR "initrd extends beyond end of memory " "(0x%08lx > 0x%08lx)\ndisabling initrd\n", (unsigned long)(INITRD_START + INITRD_SIZE), - (unsigned long)(max_low_pfn << PAGE_SHIFT)); + (unsigned long)(end_pfn << PAGE_SHIFT)); initrd_start = 0; } } @@ -726,6 +353,7 @@ * the bootmem allocator) but before get_smp_config (to allow parsing * of MADT). */ + if (!acpi_disabled) acpi_boot_init(*cmdline_p); #endif #ifdef CONFIG_X86_LOCAL_APIC @@ -737,48 +365,24 @@ init_apic_mappings(); #endif - /* * Request address space for all standard RAM and ROM resources * and also for regions reported as reserved by the e820. */ probe_roms(); - for (i = 0; i < e820.nr_map; i++) { - struct resource *res; - if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) - continue; - res = alloc_bootmem_low(sizeof(struct resource)); - switch (e820.map[i].type) { - case E820_RAM: res->name = "System RAM"; break; - case E820_ACPI: res->name = "ACPI Tables"; break; - case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; - default: res->name = "reserved"; - } - res->start = e820.map[i].addr; - res->end = res->start + e820.map[i].size - 1; - res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; - request_resource(&iomem_resource, res); - if (e820.map[i].type == E820_RAM) { - /* - * We dont't know which RAM region contains kernel data, - * so we try it repeatedly and let the resource manager - * test it. - */ - request_resource(res, &code_resource); - request_resource(res, &data_resource); - } - } + e820_reserve_resources(); + request_resource(&iomem_resource, &vram_resource); /* request I/O space for devices used on all i[345]86 PCs */ for (i = 0; i < STANDARD_IO_RESOURCES; i++) request_resource(&ioport_resource, standard_io_resources+i); - /* Tell the PCI layer not to allocate too close to the RAM area.. */ - /* ??? move this up on x86-64 */ - low_mem_size = ((max_low_pfn << PAGE_SHIFT) + 0xfffff) & ~0xfffff; - if (low_mem_size > pci_mem_start) - pci_mem_start = low_mem_size; + pci_mem_start = IOMAP_START; + +#ifdef CONFIG_GART_IOMMU + iommu_hole_init(); +#endif #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) @@ -919,11 +523,14 @@ /* Intel-defined flags: level 0x00000001 */ if ( c->cpuid_level >= 0x00000001 ) { - cpuid(0x00000001, &tfms, &junk, &junk, + __u32 misc; + cpuid(0x00000001, &tfms, &misc, &junk, &c->x86_capability[0]); c->x86 = (tfms >> 8) & 15; c->x86_model = (tfms >> 4) & 15; c->x86_mask = tfms & 15; + if (c->x86_capability[0] & (1<<19)) + c->x86_clflush_size = ((misc >> 8) & 0xff) * 8; } else { /* Have CPUID level 0 only - unheard of */ c->x86 = 4; @@ -946,12 +553,6 @@ } - printk(KERN_DEBUG "CPU: Before vendor init, caps: %08x %08x %08x, vendor = %d\n", - c->x86_capability[0], - c->x86_capability[1], - c->x86_capability[2], - c->x86_vendor); - /* * Vendor-specific initialization. In this section we * canonicalize the feature flags, meaning if there are @@ -1017,11 +618,6 @@ boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; } - printk(KERN_DEBUG "CPU: Common caps: %08x %08x %08x %08x\n", - boot_cpu_data.x86_capability[0], - boot_cpu_data.x86_capability[1], - boot_cpu_data.x86_capability[2], - boot_cpu_data.x86_capability[3]); } @@ -1147,8 +743,8 @@ } struct seq_operations cpuinfo_op = { - start: c_start, - next: c_next, - stop: c_stop, - show: show_cpuinfo, + .start =c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, }; diff -Nru a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c --- a/arch/x86_64/kernel/setup64.c Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/kernel/setup64.c Tue Oct 15 20:29:15 2002 @@ -20,10 +20,11 @@ #include #include #include +#include char x86_boot_params[2048] __initdata = {0,}; -static unsigned long cpu_initialized __initdata = 0; +unsigned long cpu_initialized __initdata = 0; struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned; @@ -34,11 +35,15 @@ extern unsigned char __per_cpu_start[], __per_cpu_end[]; -struct desc_ptr gdt_descr = { 0 /* filled in */, (unsigned long) gdt_table }; +extern struct desc_ptr cpu_gdt_descr[]; struct desc_ptr idt_descr = { 256 * 16, (unsigned long) idt_table }; char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned; +#ifndef __GENERIC_PER_CPU + +unsigned long __per_cpu_offset[NR_CPUS]; + void __init setup_per_cpu_areas(void) { unsigned long size, i; @@ -52,10 +57,15 @@ ptr = alloc_bootmem(size * NR_CPUS); for (i = 0; i < NR_CPUS; i++, ptr += size) { - cpu_pda[cpu_logical_map(i)].cpudata_offset = ptr - __per_cpu_start; + /* hide this from the compiler to avoid problems */ + unsigned long offset; + asm("subq %[b],%0" : "=r" (offset) : "0" (ptr), [b] "r" (&__per_cpu_start)); + __per_cpu_offset[i] = offset; + cpu_pda[i].cpudata_offset = offset; memcpy(ptr, __per_cpu_start, size); } } +#endif void pda_init(int cpu) { @@ -111,38 +121,48 @@ void __init cpu_init (void) { #ifdef CONFIG_SMP - int nr = stack_smp_processor_id(); + int cpu = stack_smp_processor_id(); #else - int nr = smp_processor_id(); + int cpu = smp_processor_id(); #endif - struct tss_struct * t = &init_tss[nr]; + struct tss_struct * t = &init_tss[cpu]; unsigned long v; char *estacks; struct task_struct *me; /* CPU 0 is initialised in head64.c */ - if (nr != 0) { + if (cpu != 0) { estacks = (char *)__get_free_pages(GFP_ATOMIC, 0); if (!estacks) - panic("Can't allocate exception stacks for CPU %d\n",nr); - pda_init(nr); + panic("Can't allocate exception stacks for CPU %d\n",cpu); + pda_init(cpu); } else estacks = boot_exception_stacks; me = current; - if (test_and_set_bit(nr, &cpu_initialized)) - panic("CPU#%d already initialized!\n", nr); + if (test_and_set_bit(cpu, &cpu_initialized)) + panic("CPU#%d already initialized!\n", cpu); - printk("Initializing CPU#%d\n", nr); + printk("Initializing CPU#%d\n", cpu); clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); - gdt_descr.size = (__u8*) gdt_end - (__u8*)gdt_table; - - __asm__ __volatile__("lgdt %0": "=m" (gdt_descr)); + /* + * Initialize the per-CPU GDT with the boot GDT, + * and set up the GDT descriptor: + */ + if (cpu) { + memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE); + } + + cpu_gdt_descr[cpu].size = GDT_SIZE; + cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu]; + __asm__ __volatile__("lgdt %0": "=m" (cpu_gdt_descr[cpu])); __asm__ __volatile__("lidt %0": "=m" (idt_descr)); + memcpy(me->thread.tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8); + /* * Delete NT */ @@ -177,14 +197,16 @@ estacks += EXCEPTION_STKSZ; } + t->io_map_base = INVALID_IO_BITMAP_OFFSET; + atomic_inc(&init_mm.mm_count); me->active_mm = &init_mm; if (me->mm) BUG(); - enter_lazy_tlb(&init_mm, me, nr); + enter_lazy_tlb(&init_mm, me, cpu); - set_tss_desc(nr, t); - load_TR(nr); + set_tss_desc(cpu, t); + load_TR_desc(); load_LDT(&init_mm.context); /* diff -Nru a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c --- a/arch/x86_64/kernel/signal.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/kernel/signal.c Tue Oct 15 20:29:12 2002 @@ -50,11 +50,11 @@ return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); #if DEBUG_SIG printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n", saveset, newset, ®s, regs.rip); @@ -153,10 +153,10 @@ } sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); if (restore_sigcontext(®s, &frame->uc.uc_mcontext, &eax)) { goto badframe; @@ -390,11 +390,11 @@ ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sig->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sig->siglock); } } diff -Nru a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c --- a/arch/x86_64/kernel/smp.c Tue Oct 15 20:29:14 2002 +++ b/arch/x86_64/kernel/smp.c Tue Oct 15 20:29:14 2002 @@ -15,12 +15,14 @@ #include #include #include +#include #include #include #include #include #include +#include /* * the following functions deal with sending IPIs between CPUs. @@ -75,7 +77,7 @@ * we get an APIC send error if we try to broadcast. * thus we have to avoid sending IPIs in this case. */ - if (smp_num_cpus > 1) + if (num_online_cpus() > 1) __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); } @@ -224,7 +226,7 @@ clear_bit(cpu, &flush_cpumask); out: - put_cpu(); + put_cpu_no_resched(); } static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, @@ -399,7 +401,7 @@ */ { struct call_data_struct data; - int cpus = smp_num_cpus-1; + int cpus = num_online_cpus()-1; if (!cpus) return 0; @@ -448,7 +450,6 @@ void smp_send_stop(void) { smp_call_function(stop_this_cpu, NULL, 1, 0); - smp_num_cpus = 1; local_irq_disable(); disable_local_APIC(); @@ -481,7 +482,9 @@ /* * At this point the info structure may be out of scope unless wait==1 */ + irq_enter(); (*func)(info); + irq_exit(); if (wait) { mb(); atomic_inc(&call_data->finished); diff -Nru a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c --- a/arch/x86_64/kernel/smpboot.c Tue Oct 15 20:29:23 2002 +++ b/arch/x86_64/kernel/smpboot.c Tue Oct 15 20:29:23 2002 @@ -31,6 +31,7 @@ * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug. * Maciej W. Rozycki : Bits for genuine 82489DX APICs * Andi Kleen : Changed for SMP boot into long mode. + * Rusty Russell : Hacked into shape for new "hotplug" boot process. */ #include @@ -50,12 +51,6 @@ #include #include -/* Setup configured maximum number of CPUs to activate */ -static int max_cpus = -1; - -/* Total count of live CPUs */ -int smp_num_cpus = 1; - /* Bitmask of currently online CPUs */ unsigned long cpu_online_map; @@ -65,7 +60,8 @@ volatile int x86_cpu_to_apicid[NR_CPUS]; static volatile unsigned long cpu_callin_map; -static volatile unsigned long cpu_callout_map; +volatile unsigned long cpu_callout_map; +static unsigned long smp_commenced_mask; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; @@ -74,33 +70,6 @@ int smp_threads_ready; /* - * Setup routine for controlling SMP activation - * - * Command-line option of "nosmp" or "maxcpus=0" will disable SMP - * activation entirely (the MPS table probe still happens, though). - * - * Command-line option of "maxcpus=", where is an integer - * greater than 0, limits the maximum number of CPUs activated in - * SMP mode to . - */ - -static int __init nosmp(char *str) -{ - max_cpus = 0; - return 1; -} - -__setup("nosmp", nosmp); - -static int __init maxcpus(char *str) -{ - get_option(&str, &max_cpus); - return 1; -} - -__setup("maxcpus=", maxcpus); - -/* * Trampoline 80x86 program as an array. */ @@ -117,7 +86,7 @@ static unsigned long __init setup_trampoline(void) { extern volatile __u32 tramp_gdt_ptr; - tramp_gdt_ptr = __pa_symbol(&gdt_table); + tramp_gdt_ptr = __pa_symbol(&cpu_gdt_table); memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data); return virt_to_phys(trampoline_base); } @@ -142,7 +111,7 @@ * a given CPU */ -void __init smp_store_cpu_info(int id) +static void __init smp_store_cpu_info(int id) { struct cpuinfo_x86 *c = cpu_data + id; @@ -151,29 +120,6 @@ } /* - * Architecture specific routine called by the kernel just before init is - * fired off. This allows the BP to have everything in order [we hope]. - * At the end of this all the APs will hit the system scheduling and off - * we go. Each AP will load the system gdt's and jump through the kernel - * init into idle(). At this point the scheduler will one day take over - * and give them jobs to do. smp_callin is a standard routine - * we use to track CPUs as they power up. - */ - -static atomic_t smp_commenced = ATOMIC_INIT(0); - -void __init smp_commence(void) -{ - /* - * Lets the callins below out of their loop. - */ - Dprintk("Setting commenced=1, go go go\n"); - - wmb(); - atomic_set(&smp_commenced,1); -} - -/* * TSC synchronization. * * We first check wether all CPUs have their TSC's synchronized, @@ -189,11 +135,6 @@ extern unsigned int fast_gettimeoffset_quotient; -static inline unsigned long long div64 (unsigned long long a, unsigned long b) -{ - return a/b; -} - static void __init synchronize_tsc_bp (void) { int i; @@ -202,10 +143,11 @@ long long delta; unsigned long one_usec; int buggy = 0; + extern unsigned cpu_khz; - printk("checking TSC synchronization across CPUs: "); + printk("checking TSC synchronization across %u CPUs: ",num_booting_cpus()); - one_usec = ((1<<30)/fast_gettimeoffset_quotient)*(1<<2); + one_usec = cpu_khz; atomic_set(&tsc_start_flag, 1); wmb(); @@ -224,7 +166,7 @@ /* * all APs synchronize but they loop on '== num_cpus' */ - while (atomic_read(&tsc_count_start) != smp_num_cpus-1) mb(); + while (atomic_read(&tsc_count_start) != num_booting_cpus()-1) mb(); atomic_set(&tsc_count_stop, 0); wmb(); /* @@ -242,21 +184,26 @@ /* * Wait for all APs to leave the synchronization point: */ - while (atomic_read(&tsc_count_stop) != smp_num_cpus-1) mb(); + while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1) mb(); atomic_set(&tsc_count_start, 0); wmb(); atomic_inc(&tsc_count_stop); } sum = 0; - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (test_bit(i, &cpu_callout_map)) { t0 = tsc_values[i]; sum += t0; } - avg = div64(sum, smp_num_cpus); + } + avg = sum / num_booting_cpus(); sum = 0; - for (i = 0; i < smp_num_cpus; i++) { + for (i = 0; i < NR_CPUS; i++) { + if (!test_bit(i, &cpu_callout_map)) + continue; + delta = tsc_values[i] - avg; if (delta < 0) delta = -delta; @@ -269,7 +216,7 @@ buggy = 1; printk("\n"); } - realdelta = div64(delta, one_usec); + realdelta = delta / one_usec; if (tsc_values[i] < avg) realdelta = -realdelta; @@ -288,7 +235,7 @@ int i; /* - * smp_num_cpus is not necessarily known at the time + * Not every cpu is online at the time * this gets called, so we first wait for the BP to * finish SMP initialization: */ @@ -296,14 +243,14 @@ for (i = 0; i < NR_LOOPS; i++) { atomic_inc(&tsc_count_start); - while (atomic_read(&tsc_count_start) != smp_num_cpus) mb(); + while (atomic_read(&tsc_count_start) != num_booting_cpus()) mb(); rdtscll(tsc_values[smp_processor_id()]); if (i == NR_LOOPS-1) write_tsc(0, 0); atomic_inc(&tsc_count_stop); - while (atomic_read(&tsc_count_stop) != smp_num_cpus) mb(); + while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb(); } } #undef NR_LOOPS @@ -330,7 +277,7 @@ */ phys_id = GET_APIC_ID(apic_read(APIC_ID)); cpuid = smp_processor_id(); - if (test_and_set_bit(cpuid, &cpu_online_map)) { + if (test_and_set_bit(cpuid, &cpu_callin_map)) { printk("huh, phys CPU#%d, CPU#%d already present??\n", phys_id, cpuid); BUG(); @@ -374,7 +321,7 @@ Dprintk("CALLIN, before setup_local_APIC().\n"); setup_local_APIC(); - sti(); + local_irq_enable(); #ifdef CONFIG_MTRR /* @@ -388,6 +335,8 @@ calibrate_delay(); Dprintk("Stack at about %p\n",&cpuid); + disable_APIC_timer(); + /* * Save our processor parameters */ @@ -416,9 +365,6 @@ */ int __init start_secondary(void *unused) { - int var; - printk("rsp %p\n",&var); - /* * Dont put anything before smp_callin(), SMP * booting is too fragile that we want to limit the @@ -426,14 +372,35 @@ */ cpu_init(); smp_callin(); - while (!atomic_read(&smp_commenced)) + + Dprintk("cpu %d: waiting for commence\n", smp_processor_id()); + while (!test_bit(smp_processor_id(), &smp_commenced_mask)) rep_nop(); + + Dprintk("cpu %d: setting up apic clock\n", smp_processor_id()); + setup_secondary_APIC_clock(); + + Dprintk("cpu %d: enabling apic timer\n", smp_processor_id()); + + if (nmi_watchdog == NMI_IO_APIC) { + disable_8259A_irq(0); + enable_NMI_through_LVT0(NULL); + enable_8259A_irq(0); + } + + + enable_APIC_timer(); + /* * low-memory mappings have been cleared, flush them from * the local TLBs too. */ local_flush_tlb(); + Dprintk("cpu %d eSetting cpu_online_map\n", smp_processor_id()); + set_bit(smp_processor_id(), &cpu_online_map); + wmb(); + return cpu_idle(); } @@ -469,7 +436,7 @@ * don't care about the rip and regs settings since * we'll never reschedule the forked task. */ - return do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0); + return do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL); } #if APIC_DEBUG @@ -510,91 +477,17 @@ } #endif -static void __init do_boot_cpu (int apicid) +static int __init wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip) { - struct task_struct *idle; - unsigned long send_status, accept_status, boot_status, maxlvt; - int timeout, num_starts, j, cpu; - unsigned long start_eip; - - printk("do_boot_cpu cpucount = %d\n", cpucount); - - cpu = ++cpucount; - /* - * We can't use kernel_thread since we must avoid to - * reschedule the child. - */ - idle = fork_by_hand(); - if (IS_ERR(idle)) - panic("failed fork for CPU %d", cpu); - - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ - init_idle(idle,cpu); - - x86_cpu_to_apicid[cpu] = apicid; - x86_apicid_to_cpu[apicid] = cpu; - idle->thread.rip = (unsigned long)start_secondary; -// idle->thread.rsp = (unsigned long)idle->thread_info + THREAD_SIZE - 512; - - unhash_process(idle); - - cpu_pda[cpu].pcurrent = idle; - - /* start_eip had better be page-aligned! */ - start_eip = setup_trampoline(); - - init_rsp = (unsigned long)idle->thread_info + PAGE_SIZE + 1024; - initial_code = initialize_secondary; - - printk("Booting processor %d/%d rip %lx rsp %lx rsp2 %lx\n", cpu, apicid, - start_eip, idle->thread.rsp, init_rsp); - - /* - * This grunge runs the startup process for - * the targeted processor. - */ - - atomic_set(&init_deasserted, 0); - - Dprintk("Setting warm reset code and vector.\n"); - - CMOS_WRITE(0xa, 0xf); - local_flush_tlb(); - Dprintk("1.\n"); - *((volatile unsigned short *) phys_to_virt(0x469)) = start_eip >> 4; - Dprintk("2.\n"); - *((volatile unsigned short *) phys_to_virt(0x467)) = start_eip & 0xf; - Dprintk("3.\n"); - - /* - * Be paranoid about clearing APIC errors. - */ - if (APIC_INTEGRATED(apic_version[apicid])) { - apic_read_around(APIC_SPIV); - apic_write(APIC_ESR, 0); - apic_read(APIC_ESR); - } - - /* - * Status is now clean - */ - send_status = 0; - accept_status = 0; - boot_status = 0; - - /* - * Starting actual IPI sequence... - */ + unsigned long send_status = 0, accept_status = 0; + int maxlvt, timeout, num_starts, j; Dprintk("Asserting INIT.\n"); /* * Turn INIT on target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* * Send IPI @@ -615,7 +508,7 @@ Dprintk("Deasserting INIT.\n"); /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Send IPI */ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT); @@ -634,10 +527,9 @@ * Should we send STARTUP IPIs ? * * Determine this based on the APIC version. - * If we don't have an integrated APIC, don't - * send the STARTUP IPIs. + * If we don't have an integrated APIC, don't send the STARTUP IPIs. */ - if (APIC_INTEGRATED(apic_version[apicid])) + if (APIC_INTEGRATED(apic_version[phys_apicid])) num_starts = 2; else num_starts = 0; @@ -661,12 +553,12 @@ */ /* Target chip */ - apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid)); + apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid)); /* Boot on the stack */ /* Kick the second */ apic_write_around(APIC_ICR, APIC_DM_STARTUP - | (start_eip >> 12)); + | (start_rip >> 12)); /* * Give the other CPU some time to accept the IPI. @@ -705,7 +597,89 @@ if (accept_status) printk("APIC delivery error (%lx).\n", accept_status); - if (!send_status && !accept_status) { + return (send_status | accept_status); +} + +extern unsigned long cpu_initialized; + +static void __init do_boot_cpu (int apicid) +{ + struct task_struct *idle; + unsigned long boot_error; + int timeout, cpu; + unsigned long start_rip; + + cpu = ++cpucount; + /* + * We can't use kernel_thread since we must avoid to + * reschedule the child. + */ + idle = fork_by_hand(); + if (IS_ERR(idle)) + panic("failed fork for CPU %d", cpu); + + /* + * We remove it from the pidhash and the runqueue + * once we got the process: + */ + init_idle(idle,cpu); + + x86_cpu_to_apicid[cpu] = apicid; + x86_apicid_to_cpu[apicid] = cpu; + idle->thread.rip = (unsigned long)start_secondary; +// idle->thread.rsp = (unsigned long)idle->thread_info + THREAD_SIZE - 512; + + unhash_process(idle); + + cpu_pda[cpu].pcurrent = idle; + + /* start_eip had better be page-aligned! */ + start_rip = setup_trampoline(); + + init_rsp = (unsigned long)idle->thread_info + PAGE_SIZE + 1024; + init_tss[cpu].rsp0 = init_rsp; + initial_code = initialize_secondary; + + printk("Booting processor %d/%d rip %lx rsp %lx rsp2 %lx\n", cpu, apicid, + start_rip, idle->thread.rsp, init_rsp); + + /* + * This grunge runs the startup process for + * the targeted processor. + */ + + atomic_set(&init_deasserted, 0); + + Dprintk("Setting warm reset code and vector.\n"); + + CMOS_WRITE(0xa, 0xf); + local_flush_tlb(); + Dprintk("1.\n"); + *((volatile unsigned short *) phys_to_virt(0x469)) = start_rip >> 4; + Dprintk("2.\n"); + *((volatile unsigned short *) phys_to_virt(0x467)) = start_rip & 0xf; + Dprintk("3.\n"); + + /* + * Be paranoid about clearing APIC errors. + */ + if (APIC_INTEGRATED(apic_version[apicid])) { + apic_read_around(APIC_SPIV); + apic_write(APIC_ESR, 0); + apic_read(APIC_ESR); + } + + /* + * Status is now clean + */ + boot_error = 0; + + /* + * Starting actual IPI sequence... + */ + boot_error = wakeup_secondary_via_INIT(apicid, start_rip); + + if (!boot_error) { /* * allow APs to start initializing. */ @@ -729,7 +703,7 @@ print_cpu_info(&cpu_data[cpu]); Dprintk("CPU has booted.\n"); } else { - boot_status = 1; + boot_error = 1; if (*((volatile unsigned char *)phys_to_virt(8192)) == 0xA5) /* trampoline started but...? */ @@ -742,14 +716,16 @@ #endif } } - if (send_status || accept_status || boot_status) { + if (boot_error) { x86_cpu_to_apicid[cpu] = -1; x86_apicid_to_cpu[apicid] = -1; + clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */ + clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */ cpucount--; } /* mark "stuck" area as not stuck */ - *((volatile unsigned long *)phys_to_virt(8192)) = 0; + *((volatile unsigned *)phys_to_virt(8192)) = 0; } cycles_t cacheflush_time; @@ -804,7 +780,7 @@ extern int prof_old_multiplier[NR_CPUS]; extern int prof_counter[NR_CPUS]; -void __init smp_boot_cpus(void) +static void __init smp_boot_cpus(unsigned int max_cpus) { int apicid, cpu; @@ -835,12 +811,18 @@ * We have the boot CPU online for sure. */ set_bit(0, &cpu_online_map); + set_bit(0, &cpu_callout_map); x86_apicid_to_cpu[boot_cpu_id] = 0; x86_cpu_to_apicid[0] = boot_cpu_id; - global_irq_holder = NO_PROC_ID; current_thread_info()->cpu = 0; smp_tune_scheduling(); + if (!test_bit(hard_smp_processor_id(), &phys_cpu_present_map)) { + printk("weird, boot CPU (#%d) not listed by the BIOS.\n", + hard_smp_processor_id()); + phys_cpu_present_map |= (1 << hard_smp_processor_id()); + } + /* * If we couldnt find an SMP configuration at boot time, * get out of here now! @@ -849,11 +831,11 @@ printk(KERN_NOTICE "SMP motherboard not detected.\n"); io_apic_irqs = 0; cpu_online_map = phys_cpu_present_map = 1; - smp_num_cpus = 1; + phys_cpu_present_map = 1; if (APIC_init_uniprocessor()) printk(KERN_NOTICE "Local APIC not detected." " Using dummy APIC emulation.\n"); - goto smp_done; + return; } /* @@ -875,8 +857,8 @@ printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); io_apic_irqs = 0; cpu_online_map = phys_cpu_present_map = 1; - smp_num_cpus = 1; - goto smp_done; + phys_cpu_present_map = 1; + return; } verify_local_APIC(); @@ -889,8 +871,8 @@ printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); io_apic_irqs = 0; cpu_online_map = phys_cpu_present_map = 1; - smp_num_cpus = 1; - goto smp_done; + phys_cpu_present_map = 1; + return; } connect_bsp_APIC(); @@ -941,7 +923,7 @@ */ CMOS_WRITE(0, 0xf); - *((volatile long *) phys_to_virt(0x467)) = 0; + *((volatile int *) phys_to_virt(0x467)) = 0; } /* @@ -954,7 +936,7 @@ } else { unsigned long bogosum = 0; for (cpu = 0; cpu < NR_CPUS; cpu++) - if (cpu_online_map & (1<= 2000, new mktime - * 1995-03-26 Markus Kuhn - * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 - * precision CMOS clock update - * 1996-05-03 Ingo Molnar - * fixed time warps in do_[slow|fast]_gettimeoffset() - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - * 1998-09-05 (Various) - * More robust do_fast_gettimeoffset() algorithm implemented - * (works with APM, Cyrix 6x86MX and Centaur C6), - * monotonic gettimeofday() with fast_get_timeoffset(), - * drift-proof precision TSC calibration on boot - * (C. Scott Ananian , Andrew D. - * Balsa , Philip Gladstone ; - * ported from 2.0.35 Jumbo-9 by Michael Krause ). - * 1998-12-16 Andrea Arcangeli - * Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy - * because was not accounting lost_ticks. - * 1998-12-24 Copyright (C) 1998 Andrea Arcangeli - * Fixed a xtime SMP race (we need the xtime_lock rw spinlock to - * serialize accesses to xtime/lost_ticks). */ -#include -#include #include -#include -#include -#include +#include #include -#include -#include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include - -#include - #include +#include +#include +#include +#include +#include -unsigned int cpu_khz; /* Detected as we calibrate the TSC */ - -/* Number of usecs that the last interrupt was delayed */ -int __delay_at_last_interrupt __section_delay_at_last_interrupt; - -unsigned int __last_tsc_low __section_last_tsc_low; /* lsb 32 bits of Time Stamp Counter */ - -/* Cached *multiplier* to convert TSC counts to microseconds. - * (see the equation below). - * Equal to 2^32 * (1 / (clocks per usec) ). - * Initialized in time_init. - */ -unsigned int __fast_gettimeoffset_quotient __section_fast_gettimeoffset_quotient; +u64 jiffies_64; extern rwlock_t xtime_lock; -struct timeval __xtime __section_xtime; -unsigned long __wall_jiffies __section_wall_jiffies; -struct timezone __sys_tz __section_sys_tz; -volatile unsigned long __jiffies __section_jiffies; - spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; -inline unsigned long do_gettimeoffset(void) -{ - register unsigned int eax, edx; - - /* Read the Time Stamp Counter */ +unsigned int cpu_khz; /* TSC clocks / usec, not used here */ +unsigned long hpet_period; /* fsecs / HPET clock */ +unsigned long hpet_tick; /* HPET clocks / interrupt */ +int hpet_report_lost_ticks; /* command line option */ - rdtsc(eax,edx); +struct hpet_data __hpet __section_hpet; /* address, quotient, trigger, hz */ - /* .. relative to previous jiffy (32 bits is enough) */ - eax -= last_tsc_low; /* tsc_low delta */ +volatile unsigned long __jiffies __section_jiffies; +unsigned long __wall_jiffies __section_wall_jiffies; +struct timespec __xtime __section_xtime; +struct timezone __sys_tz __section_sys_tz; - /* - * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient - * = (tsc_low delta) * (usecs_per_clock) - * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy) - * - * Using a mull instead of a divl saves up to 31 clock cycles - * in the critical path. +/* + * do_gettimeoffset() returns microseconds since last timer interrupt was + * triggered by hardware. A memory read of HPET is slower than a register read + * of TSC, but much more reliable. It's also synchronized to the timer + * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a + * timer interrupt has happened already, but hpet.trigger wasn't updated yet. + * This is not a problem, because jiffies hasn't updated either. They are bound + * together by xtime_lock. */ - __asm__("mull %2" - :"=a" (eax), "=d" (edx) - :"rm" (fast_gettimeoffset_quotient), - "0" (eax)); +static spinlock_t time_offset_lock = SPIN_LOCK_UNLOCKED; +static unsigned long timeoffset = 0; - /* our adjusted time offset in microseconds */ - return delay_at_last_interrupt + edx; +inline unsigned int do_gettimeoffset(void) +{ + unsigned long t; + rdtscll(t); + return (t - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset; } -#define TICK_SIZE tick - -spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED; - -extern spinlock_t i8259A_lock; - /* - * This version of gettimeofday has microsecond resolution - * and better than microsecond precision on fast x86 machines with TSC. + * This version of gettimeofday() has microsecond resolution and better than + * microsecond precision, as we're using at least a 10 MHz (usually 14.31818 + * MHz) HPET timer. */ + void do_gettimeofday(struct timeval *tv) { - unsigned long flags; - unsigned long usec, sec; + unsigned long flags, t; + unsigned int sec, usec; read_lock_irqsave(&xtime_lock, flags); - usec = do_gettimeoffset(); - { - unsigned long lost = jiffies - wall_jiffies; - if (lost) - usec += lost * (1000000 / HZ); - } + spin_lock(&time_offset_lock); + sec = xtime.tv_sec; - usec += xtime.tv_usec; - read_unlock_irqrestore(&xtime_lock, flags); + usec = xtime.tv_nsec / 1000; - while (usec >= 1000000) { - usec -= 1000000; - sec++; - } + t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset(); + if (t > timeoffset) timeoffset = t; + usec += timeoffset; + + spin_unlock(&time_offset_lock); + read_unlock_irqrestore(&xtime_lock, flags); - tv->tv_sec = sec; - tv->tv_usec = usec; + tv->tv_sec = sec + usec / 1000000; + tv->tv_usec = usec % 1000000; } +/* + * settimeofday() first undoes the correction that gettimeofday would do + * on the time, and then saves it. This is ugly, but has been like this for + * ages already. + */ + void do_settimeofday(struct timeval *tv) { write_lock_irq(&xtime_lock); vxtime_lock(); - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * made, and then undo it! - */ - tv->tv_usec -= do_gettimeoffset(); - tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); + + tv->tv_usec -= do_gettimeoffset() + + (jiffies - wall_jiffies) * tick_usec; while (tv->tv_usec < 0) { tv->tv_usec += 1000000; tv->tv_sec--; } - xtime = *tv; + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = (tv->tv_usec * 1000); vxtime_unlock(); time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; + write_unlock_irq(&xtime_lock); } /* - * In order to set the CMOS clock precisely, set_rtc_mmss has to be - * called 500 ms after the second nowtime has started, because when - * nowtime is written into the registers of the CMOS clock, it will - * jump to the next second precisely 500 ms later. Check the Motorola - * MC146818A or Dallas DS12887 data sheet for details. - * - * BUG: This routine does not handle hour overflow properly; it just - * sets the minutes. Usually you'll only notice that after reboot! + * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500 + * ms after the second nowtime has started, because when nowtime is written + * into the registers of the CMOS clock, it will jump to the next second + * precisely 500 ms later. Check the Motorola MC146818A or Dallas DS12887 data + * sheet for details. */ -static int set_rtc_mmss(unsigned long nowtime) + +static void set_rtc_mmss(unsigned long nowtime) { - int retval = 0; int real_seconds, real_minutes, cmos_minutes; - unsigned char save_control, save_freq_select; + unsigned char control, freq_select; + +/* + * IRQs are disabled when we're called from the timer interrupt, + * no need for spin_lock_irqsave() + */ - /* gets recalled with irq locally disabled */ spin_lock(&rtc_lock); - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); +/* + * Tell the clock it's being set and stop it. + */ + + control = CMOS_READ(RTC_CONTROL); + CMOS_WRITE(control | RTC_SET, RTC_CONTROL); + + freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE(freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT); cmos_minutes = CMOS_READ(RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(cmos_minutes); - /* - * since we're only adjusting minutes and seconds, - * don't interfere with hour overflow. This avoids - * messing with unknown time zones but requires your - * RTC not to be off by more than 15 minutes +/* + * since we're only adjusting minutes and seconds, don't interfere with hour + * overflow. This avoids messing with unknown time zones but requires your RTC + * not to be off by more than 15 minutes. Since we're calling it only when + * our clock is externally synchronized using NTP, this shouldn't be a problem. */ + real_seconds = nowtime % 60; real_minutes = nowtime / 60; - if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) real_minutes += 30; /* correct for half hour time zone */ real_minutes %= 60; if (abs(real_minutes - cmos_minutes) < 30) { - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BIN_TO_BCD(real_seconds); BIN_TO_BCD(real_minutes); - } - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", + CMOS_WRITE(real_seconds, RTC_SECONDS); + CMOS_WRITE(real_minutes, RTC_MINUTES); + } else + printk(KERN_WARNING "time.c: can't update CMOS clock from %d to %d\n", cmos_minutes, real_minutes); - retval = -1; - } - - /* The following flags have to be released exactly in this order, - * otherwise the DS12887 (popular MC146818A clone with integrated - * battery and quartz) will not reset the oscillator and will not - * update precisely 500 ms later. You won't find this mentioned in - * the Dallas Semiconductor data sheets, but who believes data - * sheets anyway ... -- Markus Kuhn - */ - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - spin_unlock(&rtc_lock); - - return retval; -} - -/* last time the cmos clock got updated */ -static long last_rtc_update; - -int timer_ack; /* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick + * The following flags have to be released exactly in this order, otherwise the + * DS12887 (popular MC146818A clone with integrated battery and quartz) will + * not reset the oscillator and will not update precisely 500 ms later. You + * won't find this mentioned in the Dallas Semiconductor data sheets, but who + * believes data sheets anyway ... -- Markus Kuhn */ -static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ -#ifdef CONFIG_X86_IO_APIC - if (timer_ack) { - /* - * Subtle, when I/O APICs are used we have to ack timer IRQ - * manually to reset the IRR bit for do_slow_gettimeoffset(). - * This will also deassert NMI lines for the watchdog if run - * on an 82489DX-based system. - */ - spin_lock(&i8259A_lock); - outb(0x0c, 0x20); - /* Ack the IRQ; AEOI will end it automatically. */ - inb(0x20); - spin_unlock(&i8259A_lock); - } -#endif - do_timer(regs); -/* - * In the SMP case we use the local APIC timer interrupt to do the - * profiling, except when we simulate SMP mode on a uniprocessor - * system, in that case we have to call the local interrupt handler. - */ -#ifndef CONFIG_X86_LOCAL_APIC - if (!user_mode(regs)) - x86_do_profile(regs->rip); -#else - if (!using_apic_timer) - smp_local_timer_interrupt(regs); -#endif - - /* - * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - if ((time_status & STA_UNSYNC) == 0 && - xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && - xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ - } -} + CMOS_WRITE(control, RTC_CONTROL); + CMOS_WRITE(freq_select, RTC_FREQ_SELECT); -static int use_tsc; + spin_unlock(&rtc_lock); +} -/* - * This is the same as the above, except we _also_ save the current - * Time Stamp Counter value at the time of the timer interrupt, so that - * we later on can estimate the time of day more exactly. - */ static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - int count; + static unsigned long rtc_update = 0; - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca +/* + * Here we are in the timer irq handler. We have irqs locally disabled (so we + * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running + * on the other CPU, so we need a lock. We also need to lock the vsyscall + * variables, because both do_timer() and us change them -arca+vojtech */ + write_lock(&xtime_lock); vxtime_lock(); - if (use_tsc) { - /* - * It is important that these two operations happen almost at - * the same time. We do the RDTSC stuff first, since it's - * faster. To avoid any inconsistencies, we need interrupts - * disabled locally. - */ - - /* - * Interrupts are just disabled locally since the timer irq - * has the SA_INTERRUPT flag set. -arca - */ - - /* read Pentium cycle counter */ + unsigned long t; + + rdtscll(t); + hpet.offset = (t - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset - 1000000L / HZ; + if (hpet.offset >= 1000000L / HZ) + hpet.offset = 0; + hpet.ticks = min_t(long, max_t(long, (t - hpet.last_tsc) * (1000000L / HZ) / (1000000L / HZ - hpet.offset), + cpu_khz * 1000/HZ * 15 / 16), cpu_khz * 1000/HZ * 16 / 15); + hpet.last_tsc = t; + } - rdtscl(last_tsc_low); +/* + * Do the timer stuff. + */ - spin_lock(&i8253_lock); - outb_p(0x00, 0x43); /* latch the count ASAP */ + do_timer(regs); - count = inb_p(0x40); /* read the latched count */ - count |= inb(0x40) << 8; - spin_unlock(&i8253_lock); +/* + * If we have an externally synchronized Linux clock, then update CMOS clock + * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy + * closest to exactly 500 ms before the next second. If the update fails, we + * don'tcare, as it'll be updated on the next turn, and the problem (time way + * off) isn't likely to go away much sooner anyway. + */ - count = ((LATCH-1) - count) * TICK_SIZE; - delay_at_last_interrupt = (count + LATCH/2) / LATCH; + if ((~time_status & STA_UNSYNC) && xtime.tv_sec > rtc_update && + abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) { + set_rtc_mmss(xtime.tv_sec); + rtc_update = xtime.tv_sec + 660; } - do_timer_interrupt(irq, NULL, regs); - vxtime_unlock(); write_unlock(&xtime_lock); - } -/* not static: needed by APM */ unsigned long get_cmos_time(void) { - unsigned int year, mon, day, hour, min, sec; - int i; + unsigned int timeout, year, mon, day, hour, min, sec; + unsigned char last, this; + +/* + * The Linux interpretation of the CMOS clock register contents: When the + * Update-In-Progress (UIP) flag goes from 1 to 0, the RTC registers show the + * second which has precisely just started. Waiting for this can take up to 1 + * second, we timeout approximately after 2.4 seconds on a machine with + * standard 8.3 MHz ISA bus. + */ spin_lock(&rtc_lock); - /* The Linux interpretation of the CMOS clock register contents: - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the - * RTC registers show the second which has precisely just started. - * Let's hope other operating systems interpret the RTC the same way. + + timeout = 1000000; + last = this = 0; + + while (timeout && last && !this) { + last = this; + this = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP; + timeout--; + } + +/* + * Here we are safe to assume the registers won't change for a whole second, so + * we just go ahead and read them. */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); hour = CMOS_READ(RTC_HOURS); day = CMOS_READ(RTC_DAY_OF_MONTH); mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + + spin_unlock(&rtc_lock); + +/* + * We know that x86-64 always uses BCD format, no need to check the config + * register. + */ + BCD_TO_BIN(sec); BCD_TO_BIN(min); BCD_TO_BIN(hour); BCD_TO_BIN(day); BCD_TO_BIN(mon); BCD_TO_BIN(year); - } - spin_unlock(&rtc_lock); + +/* + * This will work up to Dec 31, 2069. + */ + if ((year += 1900) < 1970) year += 100; + return mktime(year, mon, day, hour, min, sec); } -static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; - -/* ------ Calibrate the TSC ------- - * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). - * Too much 64-bit arithmetic here to do this cleanly in C, and for - * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) - * output busy loop as low as possible. We avoid reading the CTC registers - * directly because of the awkward 8-bit access mechanism of the 82C54 - * device. +/* + * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing + * it to the HPET timer of known frequency. */ -#define CALIBRATE_LATCH (5 * LATCH) -#define CALIBRATE_TIME (5 * 1000020/HZ) +#define TICK_COUNT 100000000 + +/* + * pit_calibrate_tsc() uses the speaker output (channel 2) of + * the PIT. This is better than using the timer interrupt output, + * because we can read the value of the speaker with just one inb(), + * where we need three i/o operations for the interrupt channel. + * We count how many ticks the TSC does in 50 ms. + */ -/* Could use 64bit arithmetic on x86-64, but the code is too fragile */ -static unsigned long __init calibrate_tsc(void) +static unsigned int __init pit_calibrate_tsc(void) { - /* Set the Gate high, disable speaker */ + unsigned long start, end; + unsigned long flags; + outb((inb(0x61) & ~0x02) | 0x01, 0x61); - /* - * Now let's take care of CTC channel 2 - * - * Set the Gate high, program CTC channel 2 for mode 0, - * (interrupt on terminal count mode), binary count, - * load 5 * LATCH count, (LSB and MSB) to begin countdown. - */ - outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ - outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ - outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ + local_irq_save(flags); + local_irq_disable(); - { - unsigned int startlow, starthigh; - unsigned int endlow, endhigh; - unsigned int count; - - rdtsc(startlow,starthigh); - count = 0; - do { - count++; - } while ((inb(0x61) & 0x20) == 0); - rdtsc(endlow,endhigh); - - last_tsc_low = endlow; - - /* Error: ECTCNEVERSET */ - if (count <= 1) - goto bad_ctc; - - __asm__("subl %2,%0\n\t" - "sbbl %3,%1" - :"=a" (endlow), "=d" (endhigh) - :"g" (startlow), "g" (starthigh), - "0" (endlow), "1" (endhigh)); - - /* Error: ECPUTOOFAST */ - if (endhigh) - goto bad_ctc; - /* Error: ECPUTOOSLOW */ - if (endlow <= CALIBRATE_TIME) - goto bad_ctc; - - __asm__("divl %2" - :"=a" (endlow), "=d" (endhigh) - :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME)); + outb(0xb0, 0x43); + outb((1193182 / (1000 / 50)) & 0xff, 0x42); + outb((1193182 / (1000 / 50)) >> 8, 0x42); + rdtscll(start); - return endlow; - } + while ((inb(0x61) & 0x20) == 0); + rdtscll(end); - /* - * The CTC wasn't reliable: we got a hit on the very first read, - * or the CPU was so fast/slow that the quotient wouldn't fit in - * 32 bits.. - */ -bad_ctc: - return 0; -} -void __init time_init(void) -{ - extern int x86_udelay_tsc; + local_irq_restore(flags); - xtime.tv_sec = get_cmos_time(); - xtime.tv_usec = 0; + return (end - start) / 50; +} -/* - * If we have APM enabled or the CPU clock speed is variable - * (CPU stops clock on HLT or slows clock to save power) - * then the TSC timestamps may diverge by up to 1 jiffy from - * 'real time' but nothing will break. - * The most frequent case is that the CPU is "woken" from a halt - * state by the timer interrupt itself, so we get 0 error. In the - * rare cases where a driver would "wake" the CPU and request a - * timestamp, the maximum error is < 1 jiffy. But timestamps are - * still perfectly ordered. - */ - - if (cpu_has_tsc) { - unsigned int tsc_quotient = calibrate_tsc(); - if (tsc_quotient) { - fast_gettimeoffset_quotient = tsc_quotient; - use_tsc = 1; - /* - * We could be more selective here I suspect - * and just enable this for the next intel chips ? - */ - x86_udelay_tsc = 1; - - /* report CPU clock rate in Hz. - * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = - * clock/second. Our precision is about 100 ppm. - */ - { unsigned int eax=0, edx=1000; - __asm__("divl %2" - :"=a" (cpu_khz), "=d" (edx) - :"r" (tsc_quotient), - "0" (eax), "1" (edx)); - printk("Detected %u.%03u MHz processor.\n", - cpu_khz / 1000, cpu_khz % 1000); - } - } - } +void __init pit_init(void) +{ + outb_p(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff, 0x40); /* LSB */ + outb_p(LATCH >> 8, 0x40); /* MSB */ +} - setup_irq(0, &irq0); +int __init time_setup(char *str) +{ + hpet_report_lost_ticks = 1; + return 1; } -static struct device device_i8253 = { - name: "i8253", - bus_id: "0040", -}; +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + +extern void __init config_acpi_tables(void); -static int time_init_driverfs(void) +void __init time_init(void) { - return register_sys_device(&device_i8253); + xtime.tv_sec = get_cmos_time(); + xtime.tv_nsec = 0; + + pit_init(); + printk(KERN_INFO "time.c: Using 1.1931816 MHz PIT timer.\n"); + setup_irq(0, &irq0); + cpu_khz = pit_calibrate_tsc(); + printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n", + cpu_khz / 1000, cpu_khz % 1000); + hpet.ticks = cpu_khz * (1000 / HZ); + rdtscll(hpet.last_tsc); } -__initcall(time_init_driverfs); +__setup("report_lost_ticks", time_setup); diff -Nru a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S --- a/arch/x86_64/kernel/trampoline.S Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/kernel/trampoline.S Tue Oct 15 20:29:15 2002 @@ -33,7 +33,7 @@ ENTRY(trampoline_data) r_base = . - + wbinvd mov %cs, %ax # Code and data in the same place mov %ax, %ds diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c Tue Oct 15 20:29:11 2002 +++ b/arch/x86_64/kernel/traps.c Tue Oct 15 20:29:11 2002 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -47,11 +48,6 @@ asmlinkage int kernel_syscall(void); extern void ia32_syscall(void); -char doublefault_stack[4*1024]; -#ifndef CONFIG_SMP -char stackfault_stack[4*1024]; -#endif - extern struct gate_struct idt_table[256]; asmlinkage void divide_error(void); @@ -101,7 +97,7 @@ } if (!strcmp(modname, "kernel")) modname = delim = ""; - return printk("[%016lx%s%s%s%s%+ld]", + return printk("<%016lx>{%s%s%s%s%+ld}", address,delim,modname,delim,symname,address-symstart); } #else @@ -114,7 +110,6 @@ #ifdef CONFIG_MODULES -extern struct module *module_list; extern struct module kernel_module; static inline int kernel_text_address(unsigned long addr) @@ -149,30 +144,59 @@ #endif +static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) +{ + int k; + for (k = 0; k < N_EXCEPTION_STACKS; k++) { + unsigned long end = init_tss[cpu].ist[k] + EXCEPTION_STKSZ; + + if (stack >= init_tss[cpu].ist[k] && stack <= end) + return (unsigned long *)end; + } + return 0; +} + /* - * These constants are for searching for possible module text - * segments. MODULE_RANGE is a guess of how much space is likely - * to be vmalloced. + * x86-64 can have upto three kernel stacks: + * process stack + * interrupt stack + * severe exception (double fault, nmi, stack fault) hardware stack + * Check and process them in order. */ -#define MODULE_RANGE (8*1024*1024) void show_trace(unsigned long *stack) { unsigned long addr; - unsigned long *irqstack, *irqstack_end; + unsigned long *irqstack, *irqstack_end, *estack_end; /* FIXME: should read the cpuid from the APIC; to still work with bogus %gs */ const int cpu = smp_processor_id(); int i; - printk("\nCall Trace: "); + printk("\nCall Trace:"); + i = 0; + + estack_end = in_exception_stack(cpu, (unsigned long)stack); + if (estack_end) { + while (stack < estack_end) { + addr = *stack++; + if (kernel_text_address(addr)) { + i += printk_address(addr); + i += printk(" "); + if (i > 50) { + printk("\n"); + i = 0; + } + } + } + i += printk(" "); + i += 7; + stack = (unsigned long *) estack_end[-2]; + } irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr); irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE + 64); - i = 1; if (stack >= irqstack && stack < irqstack_end) { - unsigned long *tstack; - printk(" "); while (stack < irqstack_end) { addr = *stack++; @@ -195,13 +219,7 @@ } stack = (unsigned long *) (irqstack_end[-1]); printk(" "); -#if 1 - tstack = (unsigned long *)(current_thread_info()+1); - if (stack < tstack || (char*)stack > (char*)tstack+THREAD_SIZE) - printk("\n" KERN_DEBUG - "no stack at the end of irqstack; stack:%p, curstack %p\n", - stack, tstack); -#endif + i += 7; } while (((long) stack & (THREAD_SIZE-1)) != 0) { @@ -260,6 +278,15 @@ show_trace((unsigned long *)rsp); } +/* + * The architecture-independent dump_stack generator + */ +void dump_stack(void) +{ + unsigned long dummy; + show_stack(&dummy); +} + void show_registers(struct pt_regs *regs) { int i; @@ -322,6 +349,7 @@ return; if (__get_user(tmp, f.filename)) f.filename = "unmapped filename"; + printk("----------- [cut here ] --------- [please bite here ] ---------\n"); printk("Kernel BUG at %.50s:%d\n", f.filename, f.line); } @@ -377,6 +405,19 @@ static void do_trap(int trapnr, int signr, char *str, struct pt_regs * regs, long error_code, siginfo_t *info) { +#ifdef CONFIG_CHECKING + { + unsigned long gs; + struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); + rdmsrl(MSR_GS_BASE, gs); + if (gs != (unsigned long)pda) { + wrmsrl(MSR_GS_BASE, pda); + printk("%s: wrong gs %lx expected %p rip %lx\n", str, gs, pda, + regs->rip); + } + } +#endif + if ((regs->cs & 3) != 0) { struct task_struct *tsk = current; @@ -452,6 +493,18 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { +#ifdef CONFIG_CHECKING + { + unsigned long gs; + struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); + rdmsrl(MSR_GS_BASE, gs); + if (gs != (unsigned long)pda) { + wrmsrl(MSR_GS_BASE, pda); + printk("general protection handler: wrong gs %lx expected %p\n", gs, pda); + } + } +#endif + if ((regs->cs & 3)!=0) { struct task_struct *tsk = current; if (exception_trace) @@ -501,8 +554,7 @@ } static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) -{ - printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); +{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); printk("Dazed and confused, but trying to continue\n"); printk("Do you have a strange power saving mode enabled?\n"); } @@ -532,6 +584,7 @@ mem_parity_error(reason, regs); if (reason & 0x40) io_check_error(reason, regs); + /* * Reassert NMI in case it became active meanwhile * as it's edge-triggered. @@ -547,6 +600,18 @@ unsigned long condition; struct task_struct *tsk = current; siginfo_t info; + +#ifdef CONFIG_CHECKING + { + unsigned long gs; + struct x8664_pda *pda = cpu_pda + stack_smp_processor_id(); + rdmsrl(MSR_GS_BASE, gs); + if (gs != (unsigned long)pda) { + wrmsrl(MSR_GS_BASE, pda); + printk("debug handler: wrong gs %lx expected %p\n", gs, pda); + } + } +#endif asm("movq %%db6,%0" : "=r" (condition)); diff -Nru a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c --- a/arch/x86_64/kernel/vsyscall.c Tue Oct 15 20:29:20 2002 +++ b/arch/x86_64/kernel/vsyscall.c Tue Oct 15 20:29:20 2002 @@ -47,7 +47,7 @@ #define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr))) -//#define NO_VSYSCALL 1 +#define NO_VSYSCALL 1 #ifdef NO_VSYSCALL #include @@ -71,51 +71,27 @@ long __vxtime_sequence[2] __section_vxtime_sequence; + static inline void do_vgettimeofday(struct timeval * tv) { - long sequence; - unsigned long usec, sec; + long sequence, t; + unsigned long sec, usec; do { - unsigned long eax, edx; - sequence = __vxtime_sequence[1]; rmb(); - /* Read the Time Stamp Counter */ - rdtsc(eax,edx); - - /* .. relative to previous jiffy (32 bits is enough) */ - eax -= __last_tsc_low; /* tsc_low delta */ - - /* - * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient - * = (tsc_low delta) * (usecs_per_clock) - * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy) - * - * Using a mull instead of a divl saves up to 31 clock cycles - * in the critical path. - */ - - edx = (eax*__fast_gettimeoffset_quotient) >> 32; - - /* our adjusted time offset in microseconds */ - usec = __delay_at_last_interrupt + edx; - - { - unsigned long lost = __jiffies - __wall_jiffies; - if (lost) - usec += lost * (1000000 / HZ); - } + rdtscll(t); sec = __xtime.tv_sec; - usec += __xtime.tv_usec; + usec = __xtime.tv_usec + + (__jiffies - __wall_jiffies) * (1000000 / HZ) + + (t - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset; rmb(); } while (sequence != __vxtime_sequence[0]); - tv->tv_sec = sec; - tv->tv_usec = usec; - timeval_normalize(tv); + tv->tv_sec = sec + usec / 1000000; + tv->tv_usec = usec % 1000000; } static inline void do_get_tz(struct timezone * tz) diff -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c --- a/arch/x86_64/kernel/x8664_ksyms.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/kernel/x8664_ksyms.c Tue Oct 15 20:29:12 2002 @@ -47,6 +47,7 @@ EXPORT_SYMBOL(boot_cpu_data); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(ioremap_nocache); EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -109,18 +110,11 @@ #ifdef CONFIG_SMP EXPORT_SYMBOL(cpu_data); -EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL_NOVERS(__write_lock_failed); EXPORT_SYMBOL_NOVERS(__read_lock_failed); -/* Global SMP irq stuff */ EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(global_irq_holder); -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); EXPORT_SYMBOL(smp_call_function); #endif diff -Nru a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile --- a/arch/x86_64/lib/Makefile Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/lib/Makefile Tue Oct 15 20:29:12 2002 @@ -2,14 +2,12 @@ # Makefile for x86_64-specific library files. # -USE_STANDARD_AS_RULE := true - EXTRA_CFLAGS_csum-partial.o := -funroll-loops L_TARGET = lib.a obj-y = csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ - thunk.o io.o clear_page.o copy_page.o + thunk.o io.o clear_page.o copy_page.o bitstr.o obj-y += memcpy.o obj-y += memmove.o obj-y += memset.o diff -Nru a/arch/x86_64/lib/bitstr.c b/arch/x86_64/lib/bitstr.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/lib/bitstr.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,25 @@ +#include + +/* Find string of zero bits in a bitmap */ +unsigned long +find_next_zero_string(unsigned long *bitmap, long start, long nbits, int len) +{ + unsigned long n, end, i; + + again: + n = find_next_zero_bit(bitmap, nbits, start); + if (n == -1) + return -1; + + /* could test bitsliced, but it's hardly worth it */ + end = n+len; + if (end >= nbits) + return -1; + for (i = n+1; i < end; i++) { + if (test_bit(i, bitmap)) { + start = i+1; + goto again; + } + } + return n; +} diff -Nru a/arch/x86_64/lib/clear_page.S b/arch/x86_64/lib/clear_page.S --- a/arch/x86_64/lib/clear_page.S Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/lib/clear_page.S Tue Oct 15 20:29:16 2002 @@ -1,7 +1,6 @@ /* * Copyright 2002 Andi Kleen, SuSE Labs. */ - #include /* @@ -13,7 +12,7 @@ movl $4096/128,%ecx movl $128,%edx loop: -#define PUT(x) movnti %rax,x*8(%rdi) +#define PUT(x) movq %rax,x*8(%rdi) PUT(0) PUT(1) PUT(2) diff -Nru a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S --- a/arch/x86_64/lib/copy_page.S Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/lib/copy_page.S Tue Oct 15 20:29:16 2002 @@ -1,6 +1,7 @@ /* * Copyright 2002 Andi Kleen, SuSE Labs. */ + #include #include #ifdef CONFIG_PREEMPT @@ -18,7 +19,9 @@ * Warning: in case of super lazy FP save this needs to be preempt_stop */ -ENTRY(copy_page) + .globl copy_page + .p2align +copy_page: prefetchnta (%rsi) prefetchnta 64(%rsi) @@ -37,22 +40,22 @@ prefetchnta 64(%rsi) loop_no_prefetch: movdqa (%rsi),%xmm0 - movdqa 1*16(%rsi),%xmm1 - movdqa 2*16(%rsi),%xmm2 - movdqa 3*16(%rsi),%xmm3 + movdqa 16(%rsi),%xmm1 + movdqa 32(%rsi),%xmm2 + movdqa 48(%rsi),%xmm3 movntdq %xmm0,(%rdi) movntdq %xmm1,16(%rdi) - movntdq %xmm2,2*16(%rdi) - movntdq %xmm3,3*16(%rdi) + movntdq %xmm2,32(%rdi) + movntdq %xmm3,48(%rdi) - movdqa 4*16(%rsi),%xmm0 - movdqa 5*16(%rsi),%xmm1 - movdqa 6*16(%rsi),%xmm2 - movdqa 7*16(%rsi),%xmm3 - movntdq %xmm0,4*16(%rdi) - movntdq %xmm1,5*16(%rdi) - movntdq %xmm2,6*16(%rdi) - movntdq %xmm3,7*16(%rdi) + movdqa 64(%rsi),%xmm0 + movdqa 80(%rsi),%xmm1 + movdqa 96(%rsi),%xmm2 + movdqa 112(%rsi),%xmm3 + movntdq %xmm0,64(%rdi) + movntdq %xmm1,80(%rdi) + movntdq %xmm2,96(%rdi) + movntdq %xmm3,112(%rdi) addq %rdx,%rdi addq %rdx,%rsi diff -Nru a/arch/x86_64/lib/copy_user.S b/arch/x86_64/lib/copy_user.S --- a/arch/x86_64/lib/copy_user.S Tue Oct 15 20:29:17 2002 +++ b/arch/x86_64/lib/copy_user.S Tue Oct 15 20:29:17 2002 @@ -6,8 +6,12 @@ #define FIX_ALIGNMENT 1 - #include +#define movnti movq /* write to cache for now */ +#define prefetch prefetcht2 + + #include #include + #include /* Standard copy_to_user with segment limit checking */ .globl copy_to_user @@ -62,7 +66,7 @@ the small movements in ioctls etc., but not penalize the bigger filesystem data copies too much. */ pushq %rbx - prefetcht0 (%rsi) + prefetch (%rsi) xorl %eax,%eax /*zero for the exception handler */ #ifdef FIX_ALIGNMENT @@ -82,7 +86,7 @@ jz loop_no_prefetch loop: - prefetchnta 64(%rsi) + prefetch 64(%rsi) loop_no_prefetch: s1: movq (%rsi),%r11 @@ -118,10 +122,11 @@ movl $8,%ebx loop_8: s9: movq (%rsi),%r8 -d9: movnti %r8,(%rdi) +d9: movq %r8,(%rdi) addq %rbx,%rdi addq %rbx,%rsi - loop loop_8 + decl %ecx + jnz loop_8 handle_7: movl %edx,%ecx @@ -132,7 +137,8 @@ d10: movb %bl,(%rdi) incq %rdi incq %rsi - loop loop_1 + decl %ecx + jnz loop_1 ende: sfence @@ -153,7 +159,8 @@ d11: movb %bl,(%rdi) incq %rsi incq %rdi - loop align_1 + decl %ecx + jnz align_1 jmp after_bad_alignment small_align: addq %r9,%rdx diff -Nru a/arch/x86_64/lib/csum-copy.S b/arch/x86_64/lib/csum-copy.S --- a/arch/x86_64/lib/csum-copy.S Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/lib/csum-copy.S Tue Oct 15 20:29:15 2002 @@ -28,6 +28,10 @@ * Wrappers need to take care of valid exception sum and zeroing. */ +/* for now - should vary this based on direction */ + #define prefetch prefetcht2 + #define movnti movq + .macro source 10: .section __ex_table,"a" @@ -163,7 +167,8 @@ movnti %rbx,(%rsi) leaq (%rsi,%rdx),%rsi /* preserve carry */ leaq (%rdi,%rdx),%rdi - loop loop_8 + decl %ecx + jnz loop_8 adcq %r9,%rax /* add in carry */ fold: @@ -188,7 +193,8 @@ movw %bx,(%rsi) addq %rdx,%rdi addq %rdx,%rsi - loop loop_1 + decl %ecx + jnz loop_1 adcw %r9w,%ax /* add in carry */ /* handle last odd byte */ @@ -235,7 +241,8 @@ movw %bx,(%rsi) addq %r10,%rdi addq %r10,%rsi - loop align_loop + decl %ecx + jnz align_loop jmp after_bad_alignment /* weird case. need to swap the sum at the end because the spec requires diff -Nru a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S --- a/arch/x86_64/lib/memcpy.S Tue Oct 15 20:29:18 2002 +++ b/arch/x86_64/lib/memcpy.S Tue Oct 15 20:29:18 2002 @@ -11,19 +11,22 @@ * Output: * rax original destination */ + + // #define FIX_ALIGNMENT .globl __memcpy .globl memcpy .p2align __memcpy: memcpy: pushq %rbx - prefetcht0 (%rsi) /*for more hopefully the hw prefetch will kick in*/ movq %rdi,%rax +#ifdef FIX_ALIGNMENT movl %edi,%ecx andl $7,%ecx jnz bad_alignment after_bad_alignment: +#endif movq %rdx,%rcx movl $64,%ebx @@ -31,30 +34,28 @@ jz handle_tail loop_64: - /* no prefetch because we assume the hw prefetcher does it already - and we have no specific temporal hint to give. XXX or give a nta - hint for the source? */ movq (%rsi),%r11 movq 8(%rsi),%r8 movq 2*8(%rsi),%r9 movq 3*8(%rsi),%r10 - movnti %r11,(%rdi) - movnti %r8,1*8(%rdi) - movnti %r9,2*8(%rdi) - movnti %r10,3*8(%rdi) + movq %r11,(%rdi) + movq %r8,1*8(%rdi) + movq %r9,2*8(%rdi) + movq %r10,3*8(%rdi) movq 4*8(%rsi),%r11 movq 5*8(%rsi),%r8 movq 6*8(%rsi),%r9 movq 7*8(%rsi),%r10 - movnti %r11,4*8(%rdi) - movnti %r8,5*8(%rdi) - movnti %r9,6*8(%rdi) - movnti %r10,7*8(%rdi) + movq %r11,4*8(%rdi) + movq %r8,5*8(%rdi) + movq %r9,6*8(%rdi) + movq %r10,7*8(%rdi) addq %rbx,%rsi addq %rbx,%rdi - loop loop_64 + decl %ecx + jnz loop_64 handle_tail: movl %edx,%ecx @@ -64,10 +65,11 @@ movl $8,%ebx loop_8: movq (%rsi),%r8 - movnti %r8,(%rdi) + movq %r8,(%rdi) addq %rbx,%rdi addq %rbx,%rsi - loop loop_8 + decl %ecx + jnz loop_8 handle_7: movl %edx,%ecx @@ -78,13 +80,16 @@ movb %r8b,(%rdi) incq %rdi incq %rsi - loop loop_1 + decl %ecx + jnz loop_1 ende: sfence popq %rbx ret + +#ifdef FIX_ALIGNMENT /* align destination */ /* This is simpleminded. For bigger blocks it may make sense to align src and dst to their aligned subset and handle the rest separately */ @@ -100,8 +105,10 @@ movb %r8b,(%rdi) incq %rdi incq %rsi - loop align_1 + decl %ecx + jnz align_1 jmp after_bad_alignment small_alignment: addq %r9,%rdx jmp handle_7 +#endif diff -Nru a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S --- a/arch/x86_64/lib/memset.S Tue Oct 15 20:29:15 2002 +++ b/arch/x86_64/lib/memset.S Tue Oct 15 20:29:15 2002 @@ -1,4 +1,4 @@ -/* Copyright 2002 Andi Kleen */ +/* Copyright 2002 Andi Kleen, SuSE Labs */ /* * ISO C memset - set a memory block to a byte value. @@ -34,16 +34,17 @@ jz handle_tail loop_64: - movnti %rax,(%rdi) - movnti %rax,8(%rdi) - movnti %rax,16(%rdi) - movnti %rax,24(%rdi) - movnti %rax,32(%rdi) - movnti %rax,40(%rdi) - movnti %rax,48(%rdi) - movnti %rax,56(%rdi) + movq %rax,(%rdi) + movq %rax,8(%rdi) + movq %rax,16(%rdi) + movq %rax,24(%rdi) + movq %rax,32(%rdi) + movq %rax,40(%rdi) + movq %rax,48(%rdi) + movq %rax,56(%rdi) addq %r8,%rdi - loop loop_64 + decl %ecx + jnz loop_64 /* Handle tail in loops. The loops should be faster than hard to predict jump tables. */ @@ -53,9 +54,10 @@ jz handle_7 shrl $3,%ecx loop_8: - movnti %rax,(%rdi) + movq %rax,(%rdi) addq $8,%rdi - loop loop_8 + decl %ecx + jnz loop_8 handle_7: movl %r11d,%ecx @@ -64,7 +66,8 @@ loop_1: movb %al,(%rdi) addq $1,%rdi - loop loop_1 + decl %ecx + jnz loop_1 ende: movq %r10,%rax @@ -73,7 +76,7 @@ bad_alignment: cmpq $7,%r11 jbe handle_7 - movnti %rax,(%rdi) /* unaligned store */ + movq %rax,(%rdi) /* unaligned store */ movq $8,%r8 subq %r9,%r8 addq %r8,%rdi diff -Nru a/arch/x86_64/lib/thunk.S b/arch/x86_64/lib/thunk.S --- a/arch/x86_64/lib/thunk.S Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/lib/thunk.S Tue Oct 15 20:29:16 2002 @@ -34,6 +34,7 @@ thunk rwsem_down_read_failed_thunk,rwsem_down_read_failed thunk rwsem_down_write_failed_thunk,rwsem_down_write_failed thunk rwsem_wake_thunk,rwsem_wake + thunk rwsem_downgrade_thunk,rwsem_downgrade_wake #endif thunk do_softirq_thunk,do_softirq diff -Nru a/arch/x86_64/lib/usercopy.c b/arch/x86_64/lib/usercopy.c --- a/arch/x86_64/lib/usercopy.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/lib/usercopy.c Tue Oct 15 20:29:12 2002 @@ -11,39 +11,49 @@ * Copy a null terminated string from userspace. */ -long __strncpy_from_user(char *dst, const char *src, long count) +#define __do_strncpy_from_user(dst,src,count,res) \ +do { \ + long __d0, __d1, __d2; \ + __asm__ __volatile__( \ + " testq %1,%1\n" \ + " jz 2f\n" \ + "0: lodsb\n" \ + " stosb\n" \ + " testb %%al,%%al\n" \ + " jz 1f\n" \ + " decq %1\n" \ + " jnz 0b\n" \ + "1: subq %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movq %5,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .quad 0b,3b\n" \ + ".previous" \ + : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ + "=&D" (__d2) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ + : "memory"); \ +} while (0) + +long +__strncpy_from_user(char *dst, const char *src, long count) { long res; - long __d0, __d1, __d2; - asm volatile( \ - " testq %1,%1\n" - " jz 2f\n" - "0: lodsb\n" - " stosb\n" - " testb %%al,%%al\n" - " loopnz 0b\n" - "1: subq %1,%0\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: movq %5,%0\n" - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 0b,3b\n" - ".previous" - : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), - "=&D" (__d2) - : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) - : "memory"); + __do_strncpy_from_user(dst, src, count, res); return res; } -long strncpy_from_user(char *dst, const char *src, long count) +long +strncpy_from_user(char *dst, const char *src, long count) { + long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) - return __strncpy_from_user(dst, src, count); - return -EFAULT; + __do_strncpy_from_user(dst, src, count, res); + return res; } /* @@ -60,13 +70,13 @@ " jz 4f\n" "0: movnti %[zero],(%[dst])\n" " addq %[eight],%[dst]\n" - " loop 0b\n" + " decl %%ecx ; jnz 0b\n" "4: movq %[size1],%%rcx\n" " testl %%ecx,%%ecx\n" " jz 2f\n" "1: movb %b[zero],(%[dst])\n" " incq %[dst]\n" - " loop 1b\n" + " decl %%ecx ; jnz 1b\n" "2: sfence\n" ".section .fixup,\"ax\"\n" "3: lea 0(%[size1],%[size8],8),%[size8]\n" diff -Nru a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile --- a/arch/x86_64/pci/Makefile Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/pci/Makefile Tue Oct 15 20:29:12 2002 @@ -1,4 +1,3 @@ -O_TARGET := pci.o obj-y := x86-64.o diff -Nru a/arch/x86_64/pci/common.c b/arch/x86_64/pci/common.c --- a/arch/x86_64/pci/common.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/pci/common.c Tue Oct 15 20:29:12 2002 @@ -133,6 +133,10 @@ pcibios_resource_survey(); +#ifdef CONFIG_GART_IOMMU + pci_iommu_init(); +#endif + /* may eventually need to do ACPI sort here. */ return 0; } @@ -185,11 +189,11 @@ return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; } -int pcibios_enable_device(struct pci_dev *dev) +int pcibios_enable_device(struct pci_dev *dev, int mask) { int err; - if ((err = pcibios_enable_resources(dev)) < 0) + if ((err = pcibios_enable_resources(dev, mask)) < 0) return err; return pcibios_enable_irq(dev); diff -Nru a/arch/x86_64/pci/fixup.c b/arch/x86_64/pci/fixup.c --- a/arch/x86_64/pci/fixup.c Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/pci/fixup.c Tue Oct 15 20:29:12 2002 @@ -41,19 +41,6 @@ } } -static void __devinit pci_fixup_ide_trash(struct pci_dev *d) -{ - int i; - - /* - * There exist PCI IDE controllers which have utter garbage - * in first four base registers. Ignore that. - */ - DBG("PCI: IDE base address trash cleared for %s\n", d->slot_name); - for(i=0; i<4; i++) - d->resource[i].start = d->resource[i].end = d->resource[i].flags = 0; -} - struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810 }, diff -Nru a/arch/x86_64/pci/pci.h b/arch/x86_64/pci/pci.h --- a/arch/x86_64/pci/pci.h Tue Oct 15 20:29:16 2002 +++ b/arch/x86_64/pci/pci.h Tue Oct 15 20:29:16 2002 @@ -29,7 +29,7 @@ extern unsigned int pcibios_max_latency; void pcibios_resource_survey(void); -int pcibios_enable_resources(struct pci_dev *); +int pcibios_enable_resources(struct pci_dev *, int); /* pci-pc.c */ diff -Nru a/arch/x86_64/pci/x86-64.c b/arch/x86_64/pci/x86-64.c --- a/arch/x86_64/pci/x86-64.c Tue Oct 15 20:29:22 2002 +++ b/arch/x86_64/pci/x86-64.c Tue Oct 15 20:29:22 2002 @@ -243,7 +243,7 @@ pcibios_assign_resources(); } -int pcibios_enable_resources(struct pci_dev *dev) +int pcibios_enable_resources(struct pci_dev *dev, int mask) { u16 cmd, old_cmd; int idx; @@ -252,6 +252,9 @@ pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for(idx=0; idx<6; idx++) { + if (!(mask & (1<resource[idx]; if (!r->start && r->end) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); diff -Nru a/arch/x86_64/vmlinux.lds.S b/arch/x86_64/vmlinux.lds.S --- a/arch/x86_64/vmlinux.lds.S Tue Oct 15 20:29:12 2002 +++ b/arch/x86_64/vmlinux.lds.S Tue Oct 15 20:29:12 2002 @@ -55,17 +55,17 @@ . = ALIGN(64); .vxtime_sequence : AT ((LOADADDR(.vsyscall_0) + SIZEOF(.vsyscall_0) + 63) & ~(63)) { *(.vxtime_sequence) } vxtime_sequence = LOADADDR(.vxtime_sequence); - .last_tsc_low : AT (LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence)) { *(.last_tsc_low) } - last_tsc_low = LOADADDR(.last_tsc_low); - .delay_at_last_interrupt : AT (LOADADDR(.last_tsc_low) + SIZEOF(.last_tsc_low)) { *(.delay_at_last_interrupt) } - delay_at_last_interrupt = LOADADDR(.delay_at_last_interrupt); - .fast_gettimeoffset_quotient : AT (LOADADDR(.delay_at_last_interrupt) + SIZEOF(.delay_at_last_interrupt)) { *(.fast_gettimeoffset_quotient) } - fast_gettimeoffset_quotient = LOADADDR(.fast_gettimeoffset_quotient); - .wall_jiffies : AT (LOADADDR(.fast_gettimeoffset_quotient) + SIZEOF(.fast_gettimeoffset_quotient)) { *(.wall_jiffies) } + . = ALIGN(16); + .hpet : AT ((LOADADDR(.vxtime_sequence) + SIZEOF(.vxtime_sequence) + 15) & ~(15)) { *(.hpet) } + hpet = LOADADDR(.hpet); + . = ALIGN(16); + .wall_jiffies : AT ((LOADADDR(.hpet) + SIZEOF(.hpet) + 15) & ~(15)) { *(.wall_jiffies) } wall_jiffies = LOADADDR(.wall_jiffies); - .sys_tz : AT (LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies)) { *(.sys_tz) } + . = ALIGN(16); + .sys_tz : AT ((LOADADDR(.wall_jiffies) + SIZEOF(.wall_jiffies) + 15) & ~(15)) { *(.sys_tz) } sys_tz = LOADADDR(.sys_tz); - .jiffies : AT (LOADADDR(.sys_tz) + SIZEOF(.sys_tz)) { *(.jiffies) } + . = ALIGN(16); + .jiffies : AT ((LOADADDR(.sys_tz) + SIZEOF(.sys_tz) + 15) & ~(15)) { *(.jiffies) } jiffies = LOADADDR(.jiffies); . = ALIGN(16); .xtime : AT ((LOADADDR(.jiffies) + SIZEOF(.jiffies) + 15) & ~(15)) { *(.xtime) } @@ -100,7 +100,6 @@ __initcall_end = .; . = ALIGN(32); __per_cpu_start = .; - . = ALIGN(64); .data.percpu : { *(.data.percpu) } __per_cpu_end = .; . = ALIGN(4096); diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile Tue Oct 15 20:29:20 2002 +++ b/drivers/Makefile Tue Oct 15 20:29:20 2002 @@ -38,7 +38,7 @@ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ -obj-$(CONFIG_BLUEZ) += bluetooth/ +obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ obj-$(CONFIG_ISDN_BOOL) += isdn/ diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c --- a/drivers/acorn/block/fd1772.c Tue Oct 15 20:29:16 2002 +++ b/drivers/acorn/block/fd1772.c Tue Oct 15 20:29:16 2002 @@ -345,8 +345,6 @@ static void fd_deselect(void); static void fd_motor_off_timer(unsigned long dummy); static void check_change(unsigned long dummy); -static __inline__ void set_head_settle_flag(void); -static __inline__ int get_head_settle_flag(void); static void floppy_irqconsequencehandler(void); static void fd_error(void); static void do_fd_action(int drive); @@ -363,7 +361,6 @@ static void finish_fdc(void); static void finish_fdc_done(int dummy); static void floppy_off(unsigned int nr); -static __inline__ void copy_buffer(void *from, void *to); static void setup_req_params(int drive); static void redo_fd_request(void); static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int @@ -543,12 +540,12 @@ * seek operation, because we don't use seeks with verify. */ -static __inline__ void set_head_settle_flag(void) +static inline void set_head_settle_flag(void) { HeadSettleFlag = FDC1772CMDADD_E; } -static __inline__ int get_head_settle_flag(void) +static inline int get_head_settle_flag(void) { int tmp = HeadSettleFlag; HeadSettleFlag = 0; @@ -560,6 +557,15 @@ /* General Interrupt Handling */ +static inline void copy_buffer(void *from, void *to) +{ + ulong *p1 = (ulong *) from, *p2 = (ulong *) to; + int cnt; + + for (cnt = 512 / 4; cnt; cnt--) + *p2++ = *p1++; +} + static void (*FloppyIRQHandler) (int status) = NULL; static void floppy_irqconsequencehandler(void) @@ -1175,16 +1181,6 @@ return 0; } -static __inline__ void copy_buffer(void *from, void *to) -{ - ulong *p1 = (ulong *) from, *p2 = (ulong *) to; - int cnt; - - for (cnt = 512 / 4; cnt; cnt--) - *p2++ = *p1++; -} - - /* This sets up the global variables describing the current request. */ static void setup_req_params(int drive) @@ -1474,9 +1470,6 @@ int drive = minor(inode->i_rdev) & 3; int old_dev; - if ((minor(inode->i_rdev) >> 2) > NUM_DISK_TYPES) - return -ENXIO; - old_dev = fd_device[drive]; if (fd_ref[drive]) @@ -1551,7 +1544,7 @@ return 0; for (i = 0; i < FD_MAX_UNITS; i++) { - disks[i] = alloc_disk(); + disks[i] = alloc_disk(1); if (!disks[i]) goto out; } diff -Nru a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c --- a/drivers/acorn/block/mfmhd.c Tue Oct 15 20:29:13 2002 +++ b/drivers/acorn/block/mfmhd.c Tue Oct 15 20:29:13 2002 @@ -1186,14 +1186,6 @@ return 0; } -static int mfm_open(struct inode *inode, struct file *file) -{ - int dev = DEVICE_NR(minor(inode->i_rdev)); - if (dev >= mfm_drives) - return -ENODEV; - return 0; -} - /* * This is to handle various kernel command line parameters * specific to this driver. @@ -1239,7 +1231,6 @@ static struct block_device_operations mfm_fops = { .owner = THIS_MODULE, - .open = mfm_open, .ioctl = mfm_ioctl, }; @@ -1336,12 +1327,11 @@ goto out3; for (i = 0; i < mfm_drives; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(64); if (!disk) goto Enomem; disk->major = MAJOR_NR; disk->first_minor = i << 6; - disk->minor_shift = 6; disk->fops = &mfm_fops; sprintf(disk->disk_name, "mfm%c", 'a'+i); mfm_gendisk[i] = disk; diff -Nru a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile --- a/drivers/acorn/char/Makefile Tue Oct 15 20:29:12 2002 +++ b/drivers/acorn/char/Makefile Tue Oct 15 20:29:12 2002 @@ -3,18 +3,11 @@ # # All the objects that export symbols. -obj-arc := keyb_arc.o -obj-rpc := keyb_ps2.o -obj-clps7500 := keyb_ps2.o defkeymap-acorn.o +obj-arc := keyb_arc.o defkeymap-acorn.o -obj-$(CONFIG_RPCMOUSE) += mouse_rpc.o -obj-$(CONFIG_ATOMWIDE_SERIAL) += serial-atomwide.o -obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o -obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o i2c.o pcf8583.o +obj-$(CONFIG_ARCH_ACORN) += i2c.o pcf8583.o obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o - -# Do the i2c and rtc last -obj-y += $(obj-$(MACHINE)) +obj-y += $(obj-$(MACHINE)) include $(TOPDIR)/Rules.make diff -Nru a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c --- a/drivers/acorn/char/i2c.c Tue Oct 15 20:29:23 2002 +++ b/drivers/acorn/char/i2c.c Tue Oct 15 20:29:23 2002 @@ -132,7 +132,7 @@ if (rtc_command(RTC_GETDATETIME, &old_rtctm)) return 0; - new_rtctm.cs = xtime.tv_usec / 10000; + new_rtctm.cs = xtime.tv_nsec / 10000000; new_rtctm.secs = nowtime % 60; nowtime /= 60; new_rtctm.mins = nowtime % 60; nowtime /= 60; new_rtctm.hours = nowtime % 24; @@ -283,7 +283,7 @@ rtc_client = client; get_rtc_time(&rtctm, &year); - xtime.tv_usec = rtctm.cs * 10000; + xtime.tv_nsec = rtctm.cs * 10000000; xtime.tv_sec = mktime(year, rtctm.mon, rtctm.mday, rtctm.hours, rtctm.mins, rtctm.secs); set_rtc = k_set_rtc_time; diff -Nru a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c --- a/drivers/acorn/char/keyb_ps2.c Tue Oct 15 20:29:15 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,416 +0,0 @@ -/* - * linux/drivers/acorn/char/keyb_ps2.c - * - * Copyright (C) 2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Keyboard driver for RiscPC ARM Linux. - * - * Note!!! This driver talks directly to the keyboard. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -extern struct tasklet_struct keyboard_tasklet; -extern void kbd_reset_kdown(void); -int kbd_read_mask; - -#define TX_DONE 0 -#define TX_SENT 1 -#define TX_SEND 2 - -static volatile int tx_state; - -#define VERSION 100 - -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN - -#define KBD_ESCAPEE0 0xe0 /* in */ -#define KBD_ESCAPEE1 0xe1 /* in */ - -#define ESCE0(x) (0xe000|(x)) -#define ESCE1(x) (0xe100|(x)) - -#define KBD_BAT 0xaa /* in */ -#define KBD_SETLEDS 0xed /* out */ -#define KBD_ECHO 0xee /* in/out */ -#define KBD_BREAK 0xf0 /* in */ -#define KBD_TYPRATEDLY 0xf3 /* out */ -#define KBD_SCANENABLE 0xf4 /* out */ -#define KBD_DEFDISABLE 0xf5 /* out */ -#define KBD_DEFAULT 0xf6 /* out */ -#define KBD_ACK 0xfa /* in */ -#define KBD_DIAGFAIL 0xfd /* in */ -#define KBD_RESEND 0xfe /* in/out */ -#define KBD_RESET 0xff /* out */ - -#define CODE_BREAK 1 -#define CODE_ESCAPEE0 2 -#define CODE_ESCAPEE1 4 -#define CODE_ESCAPE12 8 - -#define K_NONE 0x7f -#define K_ESC 0x00 -#define K_F1 0x01 -#define K_F2 0x02 -#define K_F3 0x03 -#define K_F4 0x04 -#define K_F5 0x05 -#define K_F6 0x06 -#define K_F7 0x07 -#define K_F8 0x08 -#define K_F9 0x09 -#define K_F10 0x0a -#define K_F11 0x0b -#define K_F12 0x0c -#define K_PRNT 0x0d -#define K_SCRL 0x0e -#define K_BRK 0x0f -#define K_AGR 0x10 -#define K_1 0x11 -#define K_2 0x12 -#define K_3 0x13 -#define K_4 0x14 -#define K_5 0x15 -#define K_6 0x16 -#define K_7 0x17 -#define K_8 0x18 -#define K_9 0x19 -#define K_0 0x1a -#define K_MINS 0x1b -#define K_EQLS 0x1c -#define K_BKSP 0x1e -#define K_INS 0x1f -#define K_HOME 0x20 -#define K_PGUP 0x21 -#define K_NUML 0x22 -#define KP_SLH 0x23 -#define KP_STR 0x24 -#define KP_MNS 0x3a -#define K_TAB 0x26 -#define K_Q 0x27 -#define K_W 0x28 -#define K_E 0x29 -#define K_R 0x2a -#define K_T 0x2b -#define K_Y 0x2c -#define K_U 0x2d -#define K_I 0x2e -#define K_O 0x2f -#define K_P 0x30 -#define K_LSBK 0x31 -#define K_RSBK 0x32 -#define K_ENTR 0x47 -#define K_DEL 0x34 -#define K_END 0x35 -#define K_PGDN 0x36 -#define KP_7 0x37 -#define KP_8 0x38 -#define KP_9 0x39 -#define KP_PLS 0x4b -#define K_CAPS 0x5d -#define K_A 0x3c -#define K_S 0x3d -#define K_D 0x3e -#define K_F 0x3f -#define K_G 0x40 -#define K_H 0x41 -#define K_J 0x42 -#define K_K 0x43 -#define K_L 0x44 -#define K_SEMI 0x45 -#define K_SQOT 0x46 -#define K_HASH 0x1d -#define KP_4 0x48 -#define KP_5 0x49 -#define KP_6 0x4a -#define K_LSFT 0x4c -#define K_BSLH 0x33 -#define K_Z 0x4e -#define K_X 0x4f -#define K_C 0x50 -#define K_V 0x51 -#define K_B 0x52 -#define K_N 0x53 -#define K_M 0x54 -#define K_COMA 0x55 -#define K_DOT 0x56 -#define K_FSLH 0x57 -#define K_RSFT 0x58 -#define K_UP 0x59 -#define KP_1 0x5a -#define KP_2 0x5b -#define KP_3 0x5c -#define KP_ENT 0x67 -#define K_LCTL 0x3b -#define K_LALT 0x5e -#define K_SPCE 0x5f -#define K_RALT 0x60 -#define K_RCTL 0x61 -#define K_LEFT 0x62 -#define K_DOWN 0x63 -#define K_RGHT 0x64 -#define KP_0 0x65 -#define KP_DOT 0x66 - -static unsigned char keycode_translate[256] = -{ -/* 00 */ K_NONE, K_F9 , K_NONE, K_F5 , K_F3 , K_F1 , K_F2 , K_F12 , -/* 08 */ K_NONE, K_F10 , K_F8 , K_F6 , K_F4 , K_TAB , K_AGR , K_NONE, -/* 10 */ K_NONE, K_LALT, K_LSFT, K_NONE, K_LCTL, K_Q , K_1 , K_NONE, -/* 18 */ K_NONE, K_NONE, K_Z , K_S , K_A , K_W , K_2 , K_NONE, -/* 20 */ K_NONE, K_C , K_X , K_D , K_E , K_4 , K_3 , K_NONE, -/* 28 */ K_NONE, K_SPCE, K_V , K_F , K_T , K_R , K_5 , K_NONE, -/* 30 */ K_NONE, K_N , K_B , K_H , K_G , K_Y , K_6 , K_NONE, -/* 38 */ K_NONE, K_NONE, K_M , K_J , K_U , K_7 , K_8 , K_NONE, -/* 40 */ K_NONE, K_COMA, K_K , K_I , K_O , K_0 , K_9 , K_NONE, -/* 48 */ K_NONE, K_DOT , K_FSLH, K_L , K_SEMI, K_P , K_MINS, K_NONE, -/* 50 */ K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE, -/* 58 */ K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_HASH, K_NONE, K_NONE, -/* 60 */ K_NONE, K_BSLH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE, -/* 68 */ K_NONE, KP_1 , K_NONE, KP_4 , KP_7 , K_NONE, K_NONE, K_NONE, -/* 70 */ KP_0 , KP_DOT, KP_2 , KP_5 , KP_6 , KP_8 , K_ESC , K_NUML, -/* 78 */ K_F11 , KP_PLS, KP_3 , KP_MNS, KP_STR, KP_9 , K_SCRL, K_NONE, - K_NONE, K_NONE, K_NONE, K_F7 , K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, - K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE -}; - -#ifdef CONFIG_MAGIC_SYSRQ -static unsigned char ps2kbd_sysrq_xlate[] = -{ - 27, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - '`', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '-', '=', '£', 127, 0, - 0, 0, 0, '/', '*', '#', 9, 'q', - 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', - 'p', '[', ']', '\\', 22, 23, 25, '7', - '8', '9', '-', 0, 'a', 's', 'd', 'f', - 'g', 'h', 'j', 'k', 'l', ';', '\'', 13, - '4', '5', '6', '+', 0, 0, 'z', 'x', - 'c', 'v', 'b', 'n', 'm', ',', '.', '/', - 0, 0, '1', '2', '3', 0, 0, ' ', - 0, 0, 0, 0, 0, '0', '.', 10, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; -#endif - -static inline void ps2kbd_key(unsigned int keycode, unsigned int up_flag) -{ - handle_scancode(keycode, !up_flag); -} - -static inline void ps2kbd_sendbyte(unsigned char val) -{ - int tries = 3, timeout = 1000; - - tx_state = TX_SEND; - - do { - switch (tx_state) { - case TX_SEND: - tx_state = TX_SENT; - timeout = 1000; - tries --; - - while(!(iomd_readb(IOMD_KCTRL) & (1 << 7))); - iomd_writeb(val, IOMD_KARTTX); - break; - - case TX_SENT: - udelay(1000); - if (--timeout == 0) { - printk(KERN_ERR "Keyboard timeout\n"); - tx_state = TX_DONE; - } - break; - - case TX_DONE: - break; - } - } while (tries > 0 && tx_state != TX_DONE); -} - -static unsigned char status; -static unsigned char ncodes; -static unsigned char bi; -static unsigned char buffer[4]; - -static inline void ps2kbd_reset(void) -{ - status = 0; - kbd_reset_kdown(); -} - -static void handle_rawcode(int keyval) -{ - int keysym; - - if (keyval > 0x83) { - switch (keyval) { - case KBD_ESCAPEE0: - ncodes = 2; - bi = 0; - break; - - case KBD_ESCAPEE1: - ncodes = 3; - bi = 0; - break; - - case KBD_ACK: - tx_state = TX_DONE; - return; - - case KBD_RESEND: - tx_state = TX_SEND; - return; - - case KBD_BREAK: - status |= CODE_BREAK; - return; - - default: - return; - } - } - - if (ncodes) { - buffer[bi++] = keyval; - ncodes -= 1; - if (ncodes) - return; - keysym = K_NONE; - switch (buffer[0] << 8 | buffer[1]) { - case ESCE0(0x11): keysym = K_RALT; break; - case ESCE0(0x14): keysym = K_RCTL; break; - /* - * take care of MS extra keys (actually - * 0x7d - 0x7f, but last one is already K_NONE - */ - case ESCE0(0x1f): keysym = 124; break; - case ESCE0(0x27): keysym = 125; break; - case ESCE0(0x2f): keysym = 126; break; - case ESCE0(0x4a): keysym = KP_SLH; break; - case ESCE0(0x5a): keysym = KP_ENT; break; - case ESCE0(0x69): keysym = K_END; break; - case ESCE0(0x6b): keysym = K_LEFT; break; - case ESCE0(0x6c): keysym = K_HOME; break; - case ESCE0(0x70): keysym = K_INS; break; - case ESCE0(0x71): keysym = K_DEL; break; - case ESCE0(0x72): keysym = K_DOWN; break; - case ESCE0(0x74): keysym = K_RGHT; break; - case ESCE0(0x75): keysym = K_UP; break; - case ESCE0(0x7a): keysym = K_PGDN; break; - case ESCE0(0x7c): keysym = K_PRNT; break; - case ESCE0(0x7d): keysym = K_PGUP; break; - case ESCE1(0x14): - if (buffer[2] == 0x77) - keysym = K_BRK; - break; - case ESCE0(0x12): /* ignore escaped shift key */ - status = 0; - return; - } - } else { - bi = 0; - keysym = keycode_translate[keyval]; - } - - if (keysym != K_NONE) - ps2kbd_key(keysym, status & CODE_BREAK); - status = 0; -} - -static void ps2kbd_leds(unsigned char leds) -{ - ps2kbd_sendbyte(KBD_SETLEDS); - ps2kbd_sendbyte(leds); - ps2kbd_sendbyte(KBD_SCANENABLE); -} - -static void ps2kbd_rx(int irq, void *dev_id, struct pt_regs *regs) -{ - kbd_pt_regs = regs; - - while (iomd_readb(IOMD_KCTRL) & (1 << 5)) - handle_rawcode(iomd_readb(IOMD_KARTRX)); - tasklet_schedule(&keyboard_tasklet); -} - -static void ps2kbd_tx(int irq, void *dev_id, struct pt_regs *regs) -{ -} - -static int ps2kbd_translate(unsigned char scancode, unsigned char *keycode, char rawmode) -{ - *keycode = scancode; - return 1; -} - -static char ps2kbd_unexpected_up(unsigned char scancode) -{ - return 0200; -} - -int __init ps2kbd_init_hw(void) -{ - /* Reset the keyboard state machine. */ - iomd_writeb(0, IOMD_KCTRL); - iomd_writeb(8, IOMD_KCTRL); - iomd_readb(IOMD_KARTRX); - - if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0) - panic("Could not allocate keyboard receive IRQ!"); - if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0) - panic("Could not allocate keyboard transmit IRQ!"); - - k_translate = ps2kbd_translate; - k_unexpected_up = ps2kbd_unexpected_up; - k_leds = ps2kbd_leds; -#ifdef CONFIG_MAGIC_SYSRQ - k_sysrq_xlate = ps2kbd_sysrq_xlate; - k_sysrq_key = 13; -#endif - - return 0; -} diff -Nru a/drivers/acorn/char/mouse_rpc.c b/drivers/acorn/char/mouse_rpc.c --- a/drivers/acorn/char/mouse_rpc.c Tue Oct 15 20:29:16 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,91 +0,0 @@ -/* - * linux/drivers/char/mouse_rpc.c - * - * Copyright (C) 1996-1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This handles the Acorn RiscPCs mouse. We basically have a couple - * of hardware registers that track the sensor count for the X-Y movement - * and another register holding the button state. On every VSYNC interrupt - * we read the complete state and then work out if something has changed. - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../../char/busmouse.h" - -static short old_x, old_y, old_b; -static int mousedev; - -void -mouse_rpc_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - short x, y, dx, dy; - int buttons; - - x = (short)iomd_readl(IOMD_MOUSEX); - y = (short)iomd_readl(IOMD_MOUSEY); - buttons = (__raw_readl(0xe0310000) >> 4) & 7; - - dx = x - old_x; - old_x = x; - dy = y - old_y; - old_y = y; - - if (dx || dy || buttons != old_b) { - busmouse_add_movementbuttons(mousedev, dx, dy, buttons); - old_b = buttons; - } -} - -static struct busmouse rpcmouse = { - 6, "arcmouse", NULL, NULL, NULL, 7 -}; - -static int __init mouse_rpc_init(void) -{ - mousedev = register_busmouse(&rpcmouse); - - if (mousedev < 0) - printk("rpcmouse: could not register mouse driver\n"); - else { - old_x = (short)iomd_readl(IOMD_MOUSEX); - old_y = (short)iomd_readl(IOMD_MOUSEY); - old_b = (__raw_readl(0xe0310000) >> 4) & 7; - if (request_irq(IRQ_VSYNCPULSE, mouse_rpc_irq, SA_SHIRQ, "mouse", &mousedev)) { - printk("rpcmouse: unable to allocate VSYNC interrupt\n"); - unregister_busmouse(mousedev); - mousedev = -1; - } - } - - return mousedev >= 0 ? 0 : -ENODEV; -} - -static void __exit mouse_rpc_exit(void) -{ - if (mousedev >= 0) { - unregister_busmouse(mousedev); - free_irq(IRQ_VSYNCPULSE, &mousedev); - } -} - -module_init(mouse_rpc_init); -module_exit(mouse_rpc_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("RiscPC mouse driver"); -MODULE_LICENSE("GPL"); - diff -Nru a/drivers/acorn/char/serial-atomwide.c b/drivers/acorn/char/serial-atomwide.c --- a/drivers/acorn/char/serial-atomwide.c Tue Oct 15 20:29:19 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,23 +0,0 @@ -/* - * linux/arch/arm/drivers/char/serial-atomwide.c - * - * Copyright (C) 1996 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 02-05-1996 RMK Created - * 07-05-1996 RMK Altered for greater number of cards. - * 30-07-1996 RMK Now uses generic card code. - */ -#define MY_CARD_LIST { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL } -#define MY_NUMPORTS 3 -#define MY_BAUD_BASE (7372800 / 16) -#define MY_BASE_ADDRESS(ec) \ - ecard_address ((ec), ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2) -#define MY_PORT_ADDRESS(port,cardaddr) \ - ((cardaddr) + 0x200 - (port) * 0x100) - -#include "serial-card.c" diff -Nru a/drivers/acorn/char/serial-card.c b/drivers/acorn/char/serial-card.c --- a/drivers/acorn/char/serial-card.c Tue Oct 15 20:29:17 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,120 +0,0 @@ -/* - * linux/drivers/acorn/char/serial-card.c - * - * Copyright (C) 1996-1999 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * A generic handler of serial expansion cards that use 16550s or - * the like. - * - * Definitions: - * MY_PRODS Product numbers to identify this card by - * MY_MANUS Manufacturer numbers to identify this card by - * MY_NUMPORTS Number of ports per card - * MY_BAUD_BASE Baud base for the card - * MY_INIT Initialisation routine name - * MY_BASE_ADDRESS(ec) Return base address for ports - * MY_PORT_ADDRESS - * (port,cardaddr) Return address for port using base address - * from above. - * - * Changelog: - * 30-07-1996 RMK Created - * 22-04-1998 RMK Removed old register_pre_init_serial - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifndef NUM_SERIALS -#define NUM_SERIALS MY_NUMPORTS * MAX_ECARDS -#endif - -static int serial_ports[NUM_SERIALS]; -static int serial_pcount; -static int serial_addr[NUM_SERIALS]; -static struct expansion_card *expcard[MAX_ECARDS]; - -static const card_ids serial_cids[] = { MY_CARD_LIST, { 0xffff, 0xffff } }; - -static inline int serial_register_onedev (unsigned long port, int irq) -{ - struct serial_struct req; - - memset(&req, 0, sizeof(req)); - req.baud_base = MY_BAUD_BASE; - req.irq = irq; - req.port = port; - req.flags = 0; - - return register_serial(&req); -} - -static int __init serial_card_init(void) -{ - int card = 0; - - ecard_startfind (); - - do { - struct expansion_card *ec; - unsigned long cardaddr; - int port; - - ec = ecard_find (0, serial_cids); - if (!ec) - break; - - cardaddr = MY_BASE_ADDRESS(ec); - - for (port = 0; port < MY_NUMPORTS; port ++) { - unsigned long address; - int line; - - address = MY_PORT_ADDRESS(port, cardaddr); - - line = serial_register_onedev (address, ec->irq); - if (line < 0) - break; - serial_ports[serial_pcount] = line; - serial_addr[serial_pcount] = address; - serial_pcount += 1; - } - - if (port) { - ecard_claim (ec); - expcard[card] = ec; - } else - break; - } while (++card < MAX_ECARDS); - return card ? 0 : -ENODEV; -} - -static void __exit serial_card_exit(void) -{ - int i; - - for (i = 0; i < serial_pcount; i++) { - unregister_serial(serial_ports[i]); - release_region(serial_addr[i], 8); - } - - for (i = 0; i < MAX_ECARDS; i++) - if (expcard[i]) - ecard_release (expcard[i]); -} - -MODULE_AUTHOR("Russell King"); -MODULE_LICENSE("GPL"); - -module_init(serial_card_init); -module_exit(serial_card_exit); diff -Nru a/drivers/acorn/char/serial-dualsp.c b/drivers/acorn/char/serial-dualsp.c --- a/drivers/acorn/char/serial-dualsp.c Tue Oct 15 20:29:21 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,21 +0,0 @@ -/* - * linux/drivers/acorn/char/serial-dualsp.c - * - * Copyright (C) 1996 Russell King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 30-07-1996 RMK Created - */ -#define MY_CARD_LIST { MANU_SERPORT, PROD_SERPORT_DSPORT } -#define MY_NUMPORTS 2 -#define MY_BAUD_BASE (3686400 / 16) -#define MY_BASE_ADDRESS(ec) \ - ecard_address (ec, ECARD_IOC, ECARD_SLOW) + (0x2000 >> 2) -#define MY_PORT_ADDRESS(port,cardaddress) \ - ((cardaddress) + (port) * 8) - -#include "serial-card.c" diff -Nru a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c --- a/drivers/acorn/net/ether1.c Tue Oct 15 20:29:17 2002 +++ b/drivers/acorn/net/ether1.c Tue Oct 15 20:29:17 2002 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -80,11 +81,6 @@ #define BUS_16 16 #define BUS_8 8 -static const card_ids __init ether1_cids[] = { - { MANU_ACORN, PROD_ACORN_ETHER1 }, - { 0xffff, 0xffff } -}; - /* ------------------------------------------------------------------------- */ #define DISABLEIRQS 1 @@ -647,6 +643,12 @@ { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + if (!is_valid_ether_addr(dev->dev_addr)) { + printk(KERN_WARNING "%s: invalid ethernet MAC address\n", + dev->name); + return -EINVAL; + } + if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) return -EAGAIN; @@ -971,6 +973,23 @@ return &priv->stats; } +static int +ether1_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * We'll set the MAC address on the chip when we open it. + */ + + return 0; +} + /* * Set or clear the multicast filter for this adaptor. * num_addrs == -1 Promiscuous mode, receive all packets. @@ -993,19 +1012,22 @@ printk(KERN_INFO "%s", version); } -static struct net_device * __init ether1_init_one(struct expansion_card *ec) +static int __devinit +ether1_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; struct ether1_priv *priv; - int i; + int i, ret = 0; ether1_banner(); ecard_claim(ec); dev = init_etherdev(NULL, sizeof(struct ether1_priv)); - if (!dev) + if (!dev) { + ret = -ENOMEM; goto out; + } SET_MODULE_OWNER(dev); @@ -1019,8 +1041,10 @@ request_region(dev->base_addr + 0x800, 4096, dev->name); priv = (struct ether1_priv *)dev->priv; - if ((priv->bus_type = ether1_reset(dev)) == 0) + if ((priv->bus_type = ether1_reset(dev)) == 0) { + ret = -ENODEV; goto release; + } printk(KERN_INFO "%s: ether1 in slot %d, ", dev->name, ec->slot_no); @@ -1030,16 +1054,21 @@ printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); } - if (ether1_init_2(dev)) + if (ether1_init_2(dev)) { + ret = -ENODEV; goto release; + } dev->open = ether1_open; dev->stop = ether1_close; dev->hard_start_xmit = ether1_sendpacket; dev->get_stats = ether1_getstats; dev->set_multicast_list = ether1_setmulticastlist; + dev->set_mac_address = ether1_set_mac_address; dev->tx_timeout = ether1_timeout; dev->watchdog_timeo = 5 * HZ / 100; + + ecard_set_drvdata(ec, dev); return 0; release: @@ -1049,55 +1078,46 @@ kfree(dev); out: ecard_release(ec); - return dev; + return ret; } -static struct expansion_card *e_card[MAX_ECARDS]; -static struct net_device *e_dev[MAX_ECARDS]; - -static int __init ether1_init(void) +static void __devexit ether1_remove(struct expansion_card *ec) { - int i, ret = -ENODEV; + struct net_device *dev = ecard_get_drvdata(ec); - ecard_startfind(); + ecard_set_drvdata(ec, NULL); - for (i = 0; i < MAX_ECARDS; i++) { - struct expansion_card *ec; - struct net_device *dev; + unregister_netdev(dev); - ec = ecard_find(0, ether1_cids); - if (!ec) - break; + release_region(dev->base_addr, 16); + release_region(dev->base_addr + 0x800, 4096); + kfree(dev); - dev = ether1_init_one(ec); - if (!dev) - break; + ecard_release(ec); +} - e_card[i] = ec; - e_dev[i] = dev; - ret = 0; - } +static const struct ecard_id ether1_ids[] = { + { MANU_ACORN, PROD_ACORN_ETHER1 }, + { 0xffff, 0xffff } +}; - return ret; +static struct ecard_driver ether1_driver = { + .probe = ether1_probe, + .remove = __devexit_p(ether1_remove), + .id_table = ether1_ids, + .drv = { + .name = "ether1", + }, +}; + +static int __init ether1_init(void) +{ + return ecard_register_driver(ðer1_driver); } static void __exit ether1_exit(void) { - int i; - - for (i = 0; i < MAX_ECARDS; i++) { - if (e_dev[i]) { - unregister_netdev(e_dev[i]); - release_region(e_dev[i]->base_addr, 16); - release_region(e_dev[i]->base_addr + 0x800, 4096); - kfree(e_dev[i]); - e_dev[i] = NULL; - } - if (e_card[i]) { - ecard_release(e_card[i]); - e_card[i] = NULL; - } - } + ecard_remove_driver(ðer1_driver); } module_init(ether1_init); diff -Nru a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c --- a/drivers/acorn/net/ether3.c Tue Oct 15 20:29:22 2002 +++ b/drivers/acorn/net/ether3.c Tue Oct 15 20:29:22 2002 @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -75,12 +76,6 @@ #include "ether3.h" static unsigned int net_debug = NET_DEBUG; -static const card_ids __init ether3_cids[] = { - { MANU_ANT2, PROD_ANT_ETHER3 }, - { MANU_ANT, PROD_ANT_ETHER3 }, - { MANU_ANT, PROD_ANT_ETHERB }, - { 0xffff, 0xffff } -}; static void ether3_setmulticastlist(struct net_device *dev); static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt); @@ -417,6 +412,12 @@ static int ether3_open(struct net_device *dev) { + if (!is_valid_ether_addr(dev->dev_addr)) { + printk(KERN_WARNING "%s: invalid ethernet MAC address\n", + dev->name); + return -EINVAL; + } + if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev)) return -EAGAIN; @@ -460,6 +461,23 @@ return &priv->stats; } +static int +ether3_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * We'll set the MAC address on the chip when we open it. + */ + + return 0; +} + /* * Set or clear promiscuous/multicast mode filter for this adaptor. * @@ -784,6 +802,7 @@ ether3_get_dev(struct net_device *dev, struct expansion_card *ec) { const char *name = "ether3"; + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); dev->irq = ec->irq; @@ -796,38 +815,44 @@ ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr); ec->irqmask = 0xf0; - if (ether3_addr(dev->dev_addr, ec)) - name = NULL; + ether3_addr(dev->dev_addr, ec); return name; } -static struct net_device * __init ether3_init_one(struct expansion_card *ec) +static int __devinit +ether3_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; struct dev_priv *priv; const char *name; - int i, bus_type; + int i, bus_type, ret; ether3_banner(); ecard_claim(ec); dev = init_etherdev(NULL, sizeof(struct dev_priv)); - if (!dev) + if (!dev) { + ret = -ENOMEM; goto out; + } SET_MODULE_OWNER(dev); name = ether3_get_dev(dev, ec); - if (!name) + if (!name) { + ret = -ENODEV; goto free; + } /* * this will not fail - the nature of the bus ensures this */ - if (!request_region(dev->base_addr, 128, dev->name)) + if (!request_region(dev->base_addr, 128, dev->name)) { + ret = -EBUSY; goto free; + } priv = (struct dev_priv *) dev->priv; @@ -852,11 +877,13 @@ switch (bus_type) { case BUS_UNKNOWN: printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); + ret = -ENODEV; goto failed; case BUS_8: printk(KERN_ERR "%s: %s found, but is an unsupported " "8-bit card\n", dev->name, name); + ret = -ENODEV; goto failed; default: @@ -867,16 +894,21 @@ for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); - if (ether3_init_2(dev)) + if (ether3_init_2(dev)) { + ret = -ENODEV; goto failed; + } dev->open = ether3_open; dev->stop = ether3_close; dev->hard_start_xmit = ether3_sendpacket; dev->get_stats = ether3_getstats; dev->set_multicast_list = ether3_setmulticastlist; + dev->set_mac_address = ether3_set_mac_address; dev->tx_timeout = ether3_timeout; dev->watchdog_timeo = 5 * HZ / 100; + + ecard_set_drvdata(ec, dev); return 0; failed: @@ -886,54 +918,46 @@ kfree(dev); out: ecard_release(ec); - return NULL; + return ret; } -static struct expansion_card *e_card[MAX_ECARDS]; -static struct net_device *e_dev[MAX_ECARDS]; - -static int ether3_init(void) +static void __devexit ether3_remove(struct expansion_card *ec) { - int i, ret = -ENODEV; + struct net_device *dev = ecard_get_drvdata(ec); - ecard_startfind(); + ecard_set_drvdata(ec, NULL); - for (i = 0; i < MAX_ECARDS; i++) { - struct net_device *dev; - struct expansion_card *ec; + unregister_netdev(dev); + release_region(dev->base_addr, 128); + kfree(dev); - ec = ecard_find(0, ether3_cids); - if (!ec) - break; + ecard_release(ec); +} - dev = ether3_init_one(ec); - if (!dev) - break; +static const struct ecard_id ether3_ids[] = { + { MANU_ANT2, PROD_ANT_ETHER3 }, + { MANU_ANT, PROD_ANT_ETHER3 }, + { MANU_ANT, PROD_ANT_ETHERB }, + { 0xffff, 0xffff } +}; - e_card[i] = ec; - e_dev[i] = dev; - ret = 0; - } +static struct ecard_driver ether3_driver = { + .probe = ether3_probe, + .remove = __devexit_p(ether3_remove), + .id_table = ether3_ids, + .drv = { + .name = "ether3", + }, +}; - return ret; +static int __init ether3_init(void) +{ + return ecard_register_driver(ðer3_driver); } -static void ether3_exit(void) +static void __exit ether3_exit(void) { - int i; - - for (i = 0; i < MAX_ECARDS; i++) { - if (e_dev[i]) { - unregister_netdev(e_dev[i]); - release_region(e_dev[i]->base_addr, 128); - kfree(e_dev[i]); - e_dev[i] = NULL; - } - if (e_card[i]) { - ecard_release(e_card[i]); - e_card[i] = NULL; - } - } + ecard_remove_driver(ðer3_driver); } module_init(ether3_init); diff -Nru a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c --- a/drivers/acorn/net/etherh.c Tue Oct 15 20:29:20 2002 +++ b/drivers/acorn/net/etherh.c Tue Oct 15 20:29:20 2002 @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -57,14 +58,6 @@ static unsigned int net_debug = NET_DEBUG; -static const card_ids __init etherh_cids[] = { - { MANU_ANT, PROD_ANT_ETHERM }, - { MANU_I3, PROD_I3_ETHERLAN500 }, - { MANU_I3, PROD_I3_ETHERLAN600 }, - { MANU_I3, PROD_I3_ETHERLAN600A }, - { 0xffff, 0xffff } -}; - struct etherh_priv { struct ei_device eidev; unsigned int id; @@ -441,6 +434,12 @@ { struct ei_device *ei_local = (struct ei_device *) dev->priv; + if (!is_valid_ether_addr(dev->dev_addr)) { + printk(KERN_WARNING "%s: invalid ethernet MAC address\n", + dev->name); + return -EINVAL; + } + if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev)) return -EAGAIN; @@ -483,6 +482,23 @@ return 0; } +static int +etherh_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + if (netif_running(dev)) + return -EBUSY; + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + /* + * We'll set the MAC address on the chip when we open it. + */ + + return 0; +} + /* * Initialisation */ @@ -541,21 +557,24 @@ static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16]; -static struct net_device * __init etherh_init_one(struct expansion_card *ec) +static int __init +etherh_probe(struct expansion_card *ec, const struct ecard_id *id) { struct ei_device *ei_local; struct net_device *dev; struct etherh_priv *eh; const char *dev_type; - int i, size; + int i, size, ret; etherh_banner(); ecard_claim(ec); dev = init_etherdev(NULL, sizeof(struct etherh_priv)); - if (!dev) + if (!dev) { + ret = -ENOMEM; goto out; + } /* * init_etherdev allocs and zeros dev->priv @@ -566,33 +585,33 @@ SET_MODULE_OWNER(dev); - dev->open = etherh_open; - dev->stop = etherh_close; - dev->set_config = etherh_set_config; - dev->irq = ec->irq; - dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); - dev->priv = eh; + dev->open = etherh_open; + dev->stop = etherh_close; + dev->set_mac_address = etherh_set_mac_address; + dev->set_config = etherh_set_config; + dev->irq = ec->irq; + dev->base_addr = ecard_address(ec, ECARD_MEMC, 0); /* * IRQ and control port handling */ - ec->ops = ðerh_ops; - ec->irq_data = eh; - eh->ctrl = 0; - eh->id = ec->cid.product; + if (ec->irq != 11) { + ec->ops = ðerh_ops; + ec->irq_data = eh; + } + eh->ctrl = 0; + eh->id = ec->cid.product; switch (ec->cid.product) { case PROD_ANT_ETHERM: - if (etherm_addr(dev->dev_addr)) - goto free; + etherm_addr(dev->dev_addr); dev->base_addr += ETHERM_NS8390; dev->mem_start = dev->base_addr + ETHERM_DATAPORT; eh->ctrl_port = dev->base_addr + ETHERM_CTRLPORT; break; case PROD_I3_ETHERLAN500: - if (etherh_addr(dev->dev_addr, ec)) - goto free; + etherh_addr(dev->dev_addr, ec); dev->base_addr += ETHERH500_NS8390; dev->mem_start = dev->base_addr + ETHERH500_DATAPORT; eh->ctrl_port = ecard_address (ec, ECARD_IOC, ECARD_FAST) @@ -601,8 +620,7 @@ case PROD_I3_ETHERLAN600: case PROD_I3_ETHERLAN600A: - if (etherh_addr(dev->dev_addr, ec)) - goto free; + etherh_addr(dev->dev_addr, ec); dev->base_addr += ETHERH600_NS8390; dev->mem_start = dev->base_addr + ETHERH600_DATAPORT; eh->ctrl_port = dev->base_addr + ETHERH600_CTRLPORT; @@ -611,6 +629,7 @@ default: printk(KERN_ERR "%s: unknown card type %x\n", dev->name, ec->cid.product); + ret = -ENODEV; goto free; } @@ -618,11 +637,15 @@ if (ec->cid.product == PROD_ANT_ETHERM) size <<= 3; - if (!request_region(dev->base_addr, size, dev->name)) + if (!request_region(dev->base_addr, size, dev->name)) { + ret = -EBUSY; goto free; + } - if (ethdev_init(dev)) + if (ethdev_init(dev)) { + ret = -ENODEV; goto release; + } /* * If we're in the NIC slot, make sure the IRQ is enabled @@ -690,7 +713,10 @@ etherh_reset(dev); NS8390_init(dev, 0); - return dev; + + ecard_set_drvdata(ec, dev); + + return 0; release: release_region(dev->base_addr, 16); @@ -700,67 +726,59 @@ kfree(dev); out: ecard_release(ec); - return NULL; + return ret; +} + +static void __devexit etherh_remove(struct expansion_card *ec) +{ + struct net_device *dev = ecard_get_drvdata(ec); + int size = 16; + + ecard_set_drvdata(ec, NULL); + + unregister_netdev(dev); + if (ec->cid.product == PROD_ANT_ETHERM) + size <<= 3; + release_region(dev->base_addr, size); + kfree(dev); + + ec->ops = NULL; + kfree(ec->irq_data); + ecard_release(ec); } -#define MAX_ETHERH_CARDS 2 +static const struct ecard_id etherh_ids[] = { + { MANU_ANT, PROD_ANT_ETHERM }, + { MANU_I3, PROD_I3_ETHERLAN500 }, + { MANU_I3, PROD_I3_ETHERLAN600 }, + { MANU_I3, PROD_I3_ETHERLAN600A }, + { 0xffff, 0xffff } +}; -static struct net_device *e_dev[MAX_ETHERH_CARDS]; -static struct expansion_card *e_card[MAX_ETHERH_CARDS]; +static struct ecard_driver etherh_driver = { + .probe = etherh_probe, + .remove = __devexit_p(etherh_remove), + .id_table = etherh_ids, + .drv = { + .name = "etherh", + }, +}; static int __init etherh_init(void) { - int i, ret = -ENODEV; + int i; for (i = 0; i < 16; i++) { etherh_regoffsets[i] = i; etherm_regoffsets[i] = i << 3; } - ecard_startfind(); - - for (i = 0; i < MAX_ECARDS; i++) { - struct expansion_card *ec; - struct net_device *dev; - - ec = ecard_find(0, etherh_cids); - if (!ec) - break; - - dev = etherh_init_one(ec); - if (!dev) - break; - - e_card[i] = ec; - e_dev[i] = dev; - ret = 0; - } - - return ret; + return ecard_register_driver(ðerh_driver); } static void __exit etherh_exit(void) { - int i; - - for (i = 0; i < MAX_ETHERH_CARDS; i++) { - if (e_dev[i]) { - int size; - unregister_netdev(e_dev[i]); - size = 16; - if (e_card[i]->cid.product == PROD_ANT_ETHERM) - size <<= 3; - release_region(e_dev[i]->base_addr, size); - kfree(e_dev[i]); - e_dev[i] = NULL; - } - if (e_card[i]) { - e_card[i]->ops = NULL; - kfree(e_card[i]->irq_data); - ecard_release(e_card[i]); - e_card[i] = NULL; - } - } + ecard_remove_driver(ðerh_driver); } module_init(etherh_init); diff -Nru a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c --- a/drivers/acorn/scsi/acornscsi.c Tue Oct 15 20:29:10 2002 +++ b/drivers/acorn/scsi/acornscsi.c Tue Oct 15 20:29:10 2002 @@ -319,12 +319,12 @@ target_jiffies = jiffies + 1 + cs * HZ / 100; - save_flags(flags); - sti(); + local_save_flags(flags); + local_irq_enable(); while (time_before(jiffies, target_jiffies)) barrier(); - restore_flags(flags); + local_irq_restore(flags); } static @@ -403,8 +403,9 @@ host->scsi.phase = PHASE_IDLE; host->scsi.disconnectable = 0; + memset(host->busyluns, 0, sizeof(host->busyluns)); + for (i = 0; i < 8; i++) { - host->busyluns[i] = 0; host->device[i].sync_state = SYNC_NEGOCIATE; host->device[i].disconnect_ok = 1; } @@ -1593,7 +1594,7 @@ printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", host->host->host_no, acornscsi_target(host)); host->SCpnt->device->tagged_queue = 0; - set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, &host->busyluns); + set_bit(host->SCpnt->target * 8 + host->SCpnt->lun, host->busyluns); break; #endif case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): @@ -2637,8 +2638,7 @@ printk("executing "); //#endif - save_flags(flags); - cli(); + local_irq_save(flags); switch (host->scsi.phase) { /* * If the interface is idle, and the command is 'disconnectable', @@ -2671,7 +2671,7 @@ acornscsi_abortcmd(host, host->SCpnt->tag); res = res_snooze; } - restore_flags(flags); + local_irq_restore(flags); } else if (host->origSCpnt == SCpnt) { /* * The command will be executed next, but a command diff -Nru a/drivers/acorn/scsi/acornscsi.h b/drivers/acorn/scsi/acornscsi.h --- a/drivers/acorn/scsi/acornscsi.h Tue Oct 15 20:29:16 2002 +++ b/drivers/acorn/scsi/acornscsi.h Tue Oct 15 20:29:16 2002 @@ -326,7 +326,7 @@ syncxfer_t sync_state; /* sync xfer negociation state */ unsigned char disconnect_ok:1; /* device can disconnect */ } device[8]; - unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + unsigned long busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy */ /* DMA info */ struct { diff -Nru a/drivers/acorn/scsi/cumana_1.c b/drivers/acorn/scsi/cumana_1.c --- a/drivers/acorn/scsi/cumana_1.c Tue Oct 15 20:29:12 2002 +++ b/drivers/acorn/scsi/cumana_1.c Tue Oct 15 20:29:12 2002 @@ -83,11 +83,9 @@ #define NCR5380_read(reg) cumanascsi_read(_instance, reg) #define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value) -#define do_NCR5380_intr do_cumanascsi_intr -#define NCR5380_queue_command cumanascsi_queue_command -#define NCR5380_abort cumanascsi_abort -#define NCR5380_reset cumanascsi_reset -#define NCR5380_proc_info cumanascsi_proc_info +#define NCR5380_intr cumanascsi_intr +#define NCR5380_queue_command cumanascsi_queue_command +#define NCR5380_proc_info cumanascsi_proc_info int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); @@ -159,7 +157,7 @@ outb(0x00, instance->io_port - 577); if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) { + if (request_irq(instance->irq, cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) { printk("scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = IRQ_NONE; @@ -401,8 +399,10 @@ .release = cumanascsi_release, .info = cumanascsi_info, .queuecommand = cumanascsi_queue_command, - .abort = cumanascsi_abort, - .reset = cumanascsi_reset, + .eh_abort_handler = NCR5380_abort, + .eh_device_reset_handler= NCR5380_device_reset, + .eh_bus_reset_handler = NCR5380_bus_reset, + .eh_host_reset_handler = NCR5380_host_reset, .bios_param = scsicam_bios_param, .can_queue = 16, .this_id = 7, diff -Nru a/drivers/acorn/scsi/ecoscsi.c b/drivers/acorn/scsi/ecoscsi.c --- a/drivers/acorn/scsi/ecoscsi.c Tue Oct 15 20:29:22 2002 +++ b/drivers/acorn/scsi/ecoscsi.c Tue Oct 15 20:29:22 2002 @@ -248,11 +248,9 @@ #define NCR5380_read(reg) ecoscsi_read(_instance, reg) #define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value) -#define do_NCR5380_intr do_ecoscsi_intr -#define NCR5380_queue_command ecoscsi_queue_command -#define NCR5380_abort ecoscsi_abort -#define NCR5380_reset ecoscsi_reset -#define NCR5380_proc_info ecoscsi_proc_info +#define NCR5380_intr ecoscsi_intr +#define NCR5380_queue_command ecoscsi_queue_command +#define NCR5380_proc_info ecoscsi_proc_info int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); @@ -269,8 +267,10 @@ .release = ecoscsi_release, .info = ecoscsi_info, .queuecommand = ecoscsi_queue_command, - .abort = ecoscsi_abort, - .reset = ecoscsi_reset, + .eh_abort_handler = NCR5380_abort, + .eh_device_reset_handler= NCR5380_device_reset, + .eh_bus_reset_handler = NCR5380_bus_reset, + .eh_host_reset_handler = NCR5380_host_reset, .can_queue = 16, .this_id = 7, .sg_tablesize = SG_ALL, diff -Nru a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c --- a/drivers/acorn/scsi/fas216.c Tue Oct 15 20:29:16 2002 +++ b/drivers/acorn/scsi/fas216.c Tue Oct 15 20:29:16 2002 @@ -603,7 +603,7 @@ * next buffer. */ bytes_transferred -= SCp->this_residual; - if (!next_SCp(&info->scsi.SCp)) { + if (!next_SCp(&info->scsi.SCp) && bytes_transferred) { printk(KERN_WARNING "scsi%d.%c: out of buffers\n", info->host->host_no, '0' + info->SCpnt->target); return; @@ -2300,8 +2300,8 @@ { FAS216_Info *info = (FAS216_Info *)SCpnt->host->hostdata; - printk("scsi%d.%c: "__FUNCTION__": called\n", - info->host->host_no, '0' + SCpnt->target); + printk("scsi%d.%c: %s: called\n", + info->host->host_no, '0' + SCpnt->target, __FUNCTION__); return FAILED; } @@ -2320,8 +2320,8 @@ info->stats.bus_resets += 1; - printk("scsi%d.%c: "__FUNCTION__": resetting bus\n", - info->host->host_no, '0' + SCpnt->target); + printk("scsi%d.%c: %s: resetting bus\n", + info->host->host_no, '0' + SCpnt->target, __FUNCTION__); /* * Attempt to stop all activity on this interface. @@ -2381,8 +2381,8 @@ fas216_checkmagic(info); - printk("scsi%d.%c: "__FUNCTION__": resetting host\n", - info->host->host_no, '0' + SCpnt->target); + printk("scsi%d.%c: %s: resetting host\n", + info->host->host_no, '0' + SCpnt->target, __FUNCTION__); /* * Reset the SCSI chip. diff -Nru a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h --- a/drivers/acorn/scsi/fas216.h Tue Oct 15 20:29:23 2002 +++ b/drivers/acorn/scsi/fas216.h Tue Oct 15 20:29:23 2002 @@ -288,7 +288,7 @@ neg_t sync_state; /* synchronous transfer mode */ neg_t wide_state; /* wide transfer mode */ } device[8]; - unsigned char busyluns[8]; /* array of bits indicating LUNs busy */ + unsigned long busyluns[64/sizeof(unsigned long)];/* array of bits indicating LUNs busy */ /* dma */ struct { diff -Nru a/drivers/acorn/scsi/oak.c b/drivers/acorn/scsi/oak.c --- a/drivers/acorn/scsi/oak.c Tue Oct 15 20:29:10 2002 +++ b/drivers/acorn/scsi/oak.c Tue Oct 15 20:29:10 2002 @@ -64,10 +64,8 @@ #define NCR5380_read(reg) oakscsi_read(_instance, reg) #define NCR5380_write(reg, value) oakscsi_write(_instance, reg, value) -#define do_NCR5380_intr do_oakscsi_intr +#define NCR5380_intr oakscsi_intr #define NCR5380_queue_command oakscsi_queue_command -#define NCR5380_abort oakscsi_abort -#define NCR5380_reset oakscsi_reset #define NCR5380_proc_info oakscsi_proc_info int NCR5380_proc_info(char *buffer, char **start, off_t offset, @@ -142,7 +140,7 @@ } if (instance->irq != IRQ_NONE) - if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) { + if (request_irq(instance->irq, oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) { printk("scsi%d: IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = IRQ_NONE; @@ -264,8 +262,10 @@ .release = oakscsi_release, .info = oakscsi_info, .queuecommand = oakscsi_queue_command, - .abort = oakscsi_abort, - .reset = oakscsi_reset, + .eh_abort_handler = NCR5380_abort, + .eh_device_reset_handler= NCR5380_device_reset, + .eh_bus_reset_handler = NCR5380_bus_reset, + .eh_host_reset_handler = NCR5380_host_reset, .can_queue = 16, .this_id = 7, .sg_tablesize = SG_ALL, diff -Nru a/drivers/acorn/scsi/queue.c b/drivers/acorn/scsi/queue.c --- a/drivers/acorn/scsi/queue.c Tue Oct 15 20:29:12 2002 +++ b/drivers/acorn/scsi/queue.c Tue Oct 15 20:29:12 2002 @@ -161,7 +161,7 @@ * exclude - bit array of target&lun which is busy * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available */ -Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, void *exclude) +Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude) { unsigned long flags; struct list_head *l; diff -Nru a/drivers/acorn/scsi/queue.h b/drivers/acorn/scsi/queue.h --- a/drivers/acorn/scsi/queue.h Tue Oct 15 20:29:17 2002 +++ b/drivers/acorn/scsi/queue.h Tue Oct 15 20:29:17 2002 @@ -46,7 +46,7 @@ * exclude - array of busy LUNs * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available */ -extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, void *exclude); +extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude); #define queue_add_cmd_ordered(queue,SCpnt) \ __queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE) diff -Nru a/drivers/acorn/scsi/scsi.h b/drivers/acorn/scsi/scsi.h --- a/drivers/acorn/scsi/scsi.h Tue Oct 15 20:29:12 2002 +++ b/drivers/acorn/scsi/scsi.h Tue Oct 15 20:29:12 2002 @@ -51,7 +51,7 @@ static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp) { - char c = SCp->ptr; + char c = *SCp->ptr; SCp->ptr += 1; SCp->this_residual -= 1; @@ -63,7 +63,7 @@ static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c) { - SCp->ptr = c; + *SCp->ptr = c; SCp->ptr += 1; SCp->this_residual -= 1; if (SCp->this_residual == 0) diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c --- a/drivers/atm/iphase.c Tue Oct 15 20:29:22 2002 +++ b/drivers/atm/iphase.c Tue Oct 15 20:29:22 2002 @@ -1158,18 +1158,6 @@ } if (!(skb = atm_alloc_charge(vcc, len, GFP_ATOMIC))) { - /* lets allocate an skb for now */ - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) - { - IF_ERR(printk("can't allocate memory for recv, drop pkt!\n");) - atomic_inc(&vcc->stats->rx_drop); - atm_return(vcc, atm_pdu2truesize(len)); - goto out_free_desc; - } - } - else { - IF_EVENT(printk("IA: Rx over the rx_quota %ld\n", vcc->rx_quota);) if (vcc->vci < 32) printk("Drop control packets\n"); goto out_free_desc; diff -Nru a/drivers/base/core.c b/drivers/base/core.c --- a/drivers/base/core.c Tue Oct 15 20:29:12 2002 +++ b/drivers/base/core.c Tue Oct 15 20:29:12 2002 @@ -149,36 +149,16 @@ spin_unlock(&device_lock); } -/** - * device_register - register a device - * @dev: pointer to the device structure - * - * First, make sure that the device has a parent, create - * a directory for it, then add it to the parent's list of - * children. - * - * Maintains a global list of all devices, in depth-first ordering. - * The head for that list is device_root.g_list. - */ -int device_register(struct device *dev) +int device_add(struct device *dev) { int error; if (!dev || !strlen(dev->bus_id)) return -EINVAL; - INIT_LIST_HEAD(&dev->node); - INIT_LIST_HEAD(&dev->children); - INIT_LIST_HEAD(&dev->g_list); - INIT_LIST_HEAD(&dev->driver_list); - INIT_LIST_HEAD(&dev->bus_list); - INIT_LIST_HEAD(&dev->intf_list); - spin_lock_init(&dev->lock); - atomic_set(&dev->refcount,2); - dev->present = 1; spin_lock(&device_lock); + dev->present = 1; if (dev->parent) { - get_device_locked(dev->parent); list_add_tail(&dev->g_list,&dev->parent->g_list); list_add_tail(&dev->node,&dev->parent->children); } else @@ -209,10 +189,48 @@ list_del_init(&dev->g_list); list_del_init(&dev->node); spin_unlock(&device_lock); - if (dev->parent) - put_device(dev->parent); } - put_device(dev); + return error; +} + +void device_initialize(struct device *dev) +{ + INIT_LIST_HEAD(&dev->node); + INIT_LIST_HEAD(&dev->children); + INIT_LIST_HEAD(&dev->g_list); + INIT_LIST_HEAD(&dev->driver_list); + INIT_LIST_HEAD(&dev->bus_list); + INIT_LIST_HEAD(&dev->intf_list); + spin_lock_init(&dev->lock); + atomic_set(&dev->refcount,1); + if (dev->parent) + get_device(dev->parent); +} + +/** + * device_register - register a device + * @dev: pointer to the device structure + * + * First, make sure that the device has a parent, create + * a directory for it, then add it to the parent's list of + * children. + * + * Maintains a global list of all devices, in depth-first ordering. + * The head for that list is device_root.g_list. + */ +int device_register(struct device *dev) +{ + int error; + + if (!dev || !strlen(dev->bus_id)) + return -EINVAL; + + device_initialize(dev); + if (dev->parent) + get_device(dev->parent); + error = device_add(dev); + if (error && dev->parent) + put_device(dev->parent); return error; } @@ -257,16 +275,7 @@ put_device(parent); } -/** - * device_unregister - unlink device - * @dev: device going away - * - * The device has been removed from the system, so we disavow knowledge - * of it. It might not be the final reference to the device, so we mark - * it as !present, so no more references to it can be acquired. - * In the end, we decrement the final reference count for it. - */ -void device_unregister(struct device * dev) +void device_del(struct device * dev) { spin_lock(&device_lock); dev->present = 0; @@ -293,7 +302,20 @@ /* remove the driverfs directory */ device_remove_dir(dev); +} +/** + * device_unregister - unlink device + * @dev: device going away + * + * The device has been removed from the system, so we disavow knowledge + * of it. It might not be the final reference to the device, so we mark + * it as !present, so no more references to it can be acquired. + * In the end, we decrement the final reference count for it. + */ +void device_unregister(struct device * dev) +{ + device_del(dev); put_device(dev); } diff -Nru a/drivers/block/Config.in b/drivers/block/Config.in --- a/drivers/block/Config.in Tue Oct 15 20:29:14 2002 +++ b/drivers/block/Config.in Tue Oct 15 20:29:14 2002 @@ -49,7 +49,6 @@ dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM if [ "$CONFIG_X86" = "y" -o "$CONFIG_PPC32" = "y" ]; then -# bool 'Support for Large Block Devices' CONFIG_LBD - define_bool CONFIG_LBD y + bool 'Support for Large Block Devices' CONFIG_LBD fi endmenu diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c Tue Oct 15 20:29:20 2002 +++ b/drivers/block/DAC960.c Tue Oct 15 20:29:20 2002 @@ -1962,7 +1962,6 @@ sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n); disk->major = MajorNumber; disk->first_minor = n << DAC960_MaxPartitionsBits; - disk->minor_shift = DAC960_MaxPartitionsBits; disk->fops = &DAC960_BlockDeviceOperations; } /* @@ -2200,7 +2199,7 @@ } memset(Controller, 0, sizeof(DAC960_Controller_T)); for (i = 0; i < DAC960_MaxLogicalDrives; i++) { - Controller->disks[i] = alloc_disk(); + Controller->disks[i] = alloc_disk(1<disks[i]) goto Enomem; } diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile --- a/drivers/block/Makefile Tue Oct 15 20:29:20 2002 +++ b/drivers/block/Makefile Tue Oct 15 20:29:20 2002 @@ -9,9 +9,9 @@ # export-objs := elevator.o ll_rw_blk.o loop.o genhd.o acsi.o \ - block_ioctl.o deadline-iosched.o + scsi_ioctl.o deadline-iosched.o -obj-y := elevator.o ll_rw_blk.o blkpg.o genhd.o block_ioctl.o deadline-iosched.o +obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o deadline-iosched.o obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c --- a/drivers/block/acsi.c Tue Oct 15 20:29:23 2002 +++ b/drivers/block/acsi.c Tue Oct 15 20:29:23 2002 @@ -1086,8 +1086,6 @@ unsigned int cmd, unsigned long arg ) { int dev = DEVICE_NR(inode->i_rdev); - if (dev >= NDevices) - return -EINVAL; switch (cmd) { case HDIO_GETGEO: /* HDIO_GETGEO is supported more for getting the partition's @@ -1130,13 +1128,8 @@ static int acsi_open( struct inode * inode, struct file * filp ) { - int device; - struct acsi_info_struct *aip; - - device = DEVICE_NR(inode->i_rdev); - if (device >= NDevices) - return -ENXIO; - aip = &acsi_info[device]; + int device = DEVICE_NR(inode->i_rdev); + struct acsi_info_struct *aip = &acsi_info[device]; if (access_count[device] == 0 && aip->removable) { #if 0 @@ -1729,7 +1722,7 @@ #endif err = -ENOMEM; for( i = 0; i < NDevices; ++i ) { - acsi_gendisk[i] = alloc_disk(); + acsi_gendisk[i] = alloc_disk(16); if (!acsi_gendisk[i]) goto out4; } @@ -1739,7 +1732,10 @@ sprintf(disk->disk_name, "ad%c", 'a'+i); disk->major = MAJOR_NR; disk->first_minor = i << 4; - disk->minor_shift = (acsi_info[i].type==HARDDISK)?4:0; + if (acsi_info[i].type != HARDDISK) { + disk->minor_shift = 0; + disk->minors = 1; + } disk->fops = &acsi_fops; set_capacity(disk, acsi_info[i].size); add_disk(disk); diff -Nru a/drivers/block/amiflop.c b/drivers/block/amiflop.c --- a/drivers/block/amiflop.c Tue Oct 15 20:29:16 2002 +++ b/drivers/block/amiflop.c Tue Oct 15 20:29:16 2002 @@ -1607,9 +1607,6 @@ if (!kdev_same(old_dev, inode->i_rdev)) return -EBUSY; - if (unit[drive].type->code == FD_NODRIVE) - return -ENODEV; - if (filp && filp->f_mode & 3) { check_disk_change(inode->i_bdev); if (filp->f_mode & 2 ) { @@ -1683,11 +1680,6 @@ int changed; static int first_time = 1; - if (major(dev) != MAJOR_NR) { - printk(KERN_CRIT "floppy_change: not a floppy\n"); - return 0; - } - if (first_time) changed = first_time--; else { @@ -1735,7 +1727,7 @@ fd_probe(drive); if (unit[drive].type->code == FD_NODRIVE) continue; - disk = alloc_disk(); + disk = alloc_disk(1); if (!disk) { unit[drive].type->code = FD_NODRIVE; continue; @@ -1751,7 +1743,6 @@ printk("fd%d ",drive); disk->major = MAJOR_NR; disk->first_minor = drive; - disk->minor_shift = 0; disk->fops = &floppy_fops; sprintf(disk->disk_name, "fd%d", drive); set_capacity(disk, 880*2); diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c --- a/drivers/block/ataflop.c Tue Oct 15 20:29:12 2002 +++ b/drivers/block/ataflop.c Tue Oct 15 20:29:12 2002 @@ -1358,12 +1358,6 @@ static int check_floppy_change (kdev_t dev) { unsigned int drive = minor(dev) & 0x03; - - if (major(dev) != MAJOR_NR) { - printk(KERN_ERR "floppy_changed: not a floppy\n"); - return 0; - } - if (test_bit (drive, &fake_change)) { /* simulated change (e.g. after formatting) */ return 1; @@ -1855,17 +1849,11 @@ static int floppy_open( struct inode *inode, struct file *filp ) { - int drive, type; - int old_dev; + int drive = minor(inode->i_rdev) & 3; + int type = minor(inode->i_rdev) >> 2; + int old_dev = fd_device[drive]; - drive = minor(inode->i_rdev) & 3; - type = minor(inode->i_rdev) >> 2; DPRINT(("fd_open: type=%d\n",type)); - if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS) - return -ENXIO; - - old_dev = fd_device[drive]; - if (fd_ref[drive] && old_dev != minor(inode->i_rdev)) return -EBUSY; @@ -1949,7 +1937,7 @@ } for (i = 0; i < FD_MAX_UNITS; i++) { - unit[i].disk = alloc_disk(); + unit[i].disk = alloc_disk(1); if (!unit[i].disk) goto Enomem; } diff -Nru a/drivers/block/blkpg.c b/drivers/block/blkpg.c --- a/drivers/block/blkpg.c Tue Oct 15 20:29:12 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,310 +0,0 @@ -/* - * Partition table and disk geometry handling - * - * This obsoletes the partition-handling code in genhd.c: - * Userspace can look at a disk in arbitrary format and tell - * the kernel what partitions there are on the disk, and how - * these should be numbered. - * It also allows one to repartition a disk that is being used. - * - * A single ioctl with lots of subfunctions: - * - * Device number stuff: - * get_whole_disk() (given the device number of a partition, find - * the device number of the encompassing disk) - * get_all_partitions() (given the device number of a disk, return the - * device numbers of all its known partitions) - * - * Partition stuff: - * add_partition() - * delete_partition() - * test_partition_in_use() (also for test_disk_in_use) - * - * Geometry stuff: - * get_geometry() - * set_geometry() - * get_bios_drivedata() - * - * For today, only the partition stuff - aeb, 990515 - */ - -#include -#include /* for BLKROSET, ... */ -#include /* for capable() */ -#include /* for set_device_ro() */ -#include -#include -#include /* for EXPORT_SYMBOL */ -#include -#include - -#include - -/* - * What is the data describing a partition? - * - * 1. a device number (kdev_t) - * 2. a starting sector and number of sectors (hd_struct) - * given in the part[] array of the gendisk structure for the drive. - * - * The number of sectors is replicated in the sizes[] array of - * the gendisk structure for the major, which again is copied to - * the blk_size[][] array. - * (However, hd_struct has the number of 512-byte sectors, - * g->sizes[] and blk_size[][] have the number of 1024-byte blocks.) - * Note that several drives may have the same major. - */ - -/* - * Add a partition. - * - * returns: EINVAL: bad parameters - * ENXIO: cannot find drive - * EBUSY: proposed partition overlaps an existing one - * or has the same number as an existing one - * 0: all OK. - */ -int add_partition(struct block_device *bdev, struct blkpg_partition *p) -{ - struct gendisk *g; - long long ppstart, pplength; - int part, i; - - /* convert bytes to sectors */ - ppstart = (p->start >> 9); - pplength = (p->length >> 9); - - /* check for fit in a hd_struct */ - if (sizeof(sector_t) == sizeof(long) && - sizeof(long long) > sizeof(long)) { - long pstart, plength; - pstart = ppstart; - plength = pplength; - if (pstart != ppstart || plength != pplength - || pstart < 0 || plength < 0) - return -EINVAL; - } - - /* find the drive major */ - g = get_gendisk(bdev->bd_dev, &part); - if (!g) - return -ENXIO; - - /* existing drive? */ - - /* drive and partition number OK? */ - if (bdev != bdev->bd_contains) - return -EINVAL; - if (part) - BUG(); - if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) - return -EINVAL; - - /* partition number in use? */ - if (g->part[p->pno - 1].nr_sects != 0) - return -EBUSY; - - /* overlap? */ - for (i = 0; i < (1<minor_shift) - 1; i++) - if (!(ppstart+pplength <= g->part[i].start_sect || - ppstart >= g->part[i].start_sect + g->part[i].nr_sects)) - return -EBUSY; - - /* all seems OK */ - g->part[p->pno - 1].start_sect = ppstart; - g->part[p->pno - 1].nr_sects = pplength; - update_partition(g, p->pno); - return 0; -} - -/* - * Delete a partition given by partition number - * - * returns: EINVAL: bad parameters - * ENXIO: cannot find partition - * EBUSY: partition is busy - * 0: all OK. - * - * Note that the dev argument refers to the entire disk, not the partition. - */ -int del_partition(struct block_device *bdev, struct blkpg_partition *p) -{ - struct gendisk *g; - struct block_device *bdevp; - int part; - int holder; - - /* find the drive major */ - g = get_gendisk(bdev->bd_dev, &part); - if (!g) - return -ENXIO; - if (bdev != bdev->bd_contains) - return -EINVAL; - if (part) - BUG(); - if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) - return -EINVAL; - - /* existing drive and partition? */ - if (g->part[p->pno - 1].nr_sects == 0) - return -ENXIO; - - /* partition in use? Incomplete check for now. */ - bdevp = bdget(MKDEV(g->major, g->first_minor + p->pno)); - if (!bdevp) - return -ENOMEM; - if (bd_claim(bdevp, &holder) < 0) { - bdput(bdevp); - return -EBUSY; - } - - /* all seems OK */ - fsync_bdev(bdevp); - invalidate_bdev(bdevp, 0); - - g->part[p->pno - 1].start_sect = 0; - g->part[p->pno - 1].nr_sects = 0; - update_partition(g, p->pno); - bd_release(bdevp); - bdput(bdevp); - - return 0; -} - -int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) -{ - struct blkpg_ioctl_arg a; - struct blkpg_partition p; - int len; - - if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) - return -EFAULT; - - switch (a.op) { - case BLKPG_ADD_PARTITION: - case BLKPG_DEL_PARTITION: - len = a.datalen; - if (len < sizeof(struct blkpg_partition)) - return -EINVAL; - if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) - return -EFAULT; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (a.op == BLKPG_ADD_PARTITION) - return add_partition(bdev, &p); - else - return del_partition(bdev, &p); - default: - return -EINVAL; - } -} - -/* - * Common ioctl's for block devices - */ -int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) -{ - request_queue_t *q; - u64 ullval = 0; - int intval; - unsigned short usval; - kdev_t dev = to_kdev_t(bdev->bd_dev); - int holder; - struct backing_dev_info *bdi; - - switch (cmd) { - case BLKROSET: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (get_user(intval, (int *)(arg))) - return -EFAULT; - set_device_ro(dev, intval); - return 0; - case BLKROGET: - intval = (bdev_read_only(bdev) != 0); - return put_user(intval, (int *)(arg)); - - case BLKRASET: - case BLKFRASET: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - bdi = blk_get_backing_dev_info(bdev); - if (bdi == NULL) - return -ENOTTY; - bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE; - return 0; - - case BLKRAGET: - case BLKFRAGET: - if (!arg) - return -EINVAL; - bdi = blk_get_backing_dev_info(bdev); - if (bdi == NULL) - return -ENOTTY; - return put_user((bdi->ra_pages * PAGE_CACHE_SIZE) / 512, - (long *)arg); - - case BLKSECTGET: - if ((q = bdev_get_queue(bdev)) == NULL) - return -EINVAL; - - usval = q->max_sectors; - blk_put_queue(q); - return put_user(usval, (unsigned short *)arg); - - case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - fsync_bdev(bdev); - invalidate_bdev(bdev, 0); - return 0; - - case BLKSSZGET: - /* get block device hardware sector size */ - intval = bdev_hardsect_size(bdev); - return put_user(intval, (int *) arg); - - case BLKGETSIZE: - { - unsigned long ret; - /* size in sectors, works up to 2 TB */ - ullval = bdev->bd_inode->i_size; - ret = ullval >> 9; - if ((u64)ret != (ullval >> 9)) - return -EFBIG; - return put_user(ret, (unsigned long *) arg); - } - - case BLKGETSIZE64: - /* size in bytes */ - ullval = bdev->bd_inode->i_size; - return put_user(ullval, (u64 *) arg); - - case BLKPG: - return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg); - case BLKBSZGET: - /* get the logical block size (cf. BLKSSZGET) */ - intval = block_size(bdev); - return put_user(intval, (int *) arg); - - case BLKBSZSET: - /* set the logical block size */ - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!arg) - return -EINVAL; - if (get_user(intval, (int *) arg)) - return -EFAULT; - if (intval > PAGE_SIZE || intval < 512 || - (intval & (intval - 1))) - return -EINVAL; - if (bd_claim(bdev, &holder) < 0) - return -EBUSY; - set_blocksize(bdev, intval); - bd_release(bdev); - return 0; - - default: - return -EINVAL; - } -} diff -Nru a/drivers/block/block_ioctl.c b/drivers/block/block_ioctl.c --- a/drivers/block/block_ioctl.c Tue Oct 15 20:29:23 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2001 Jens Axboe - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public Licens - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -int blk_do_rq(request_queue_t *q, struct request *rq) -{ - DECLARE_COMPLETION(wait); - int err = 0; - - rq->flags |= REQ_NOMERGE; - rq->waiting = &wait; - elv_add_request(q, rq, 1); - generic_unplug_device(q); - wait_for_completion(&wait); - - /* - * for now, never retry anything - */ - if (rq->errors) - err = -EIO; - - return err; -} - -int block_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) -{ - request_queue_t *q; - struct request *rq; - int close = 0, err; - - q = bdev_get_queue(bdev); - if (!q) - return -ENXIO; - - switch (cmd) { - case CDROMCLOSETRAY: - close = 1; - case CDROMEJECT: - rq = blk_get_request(q, WRITE, __GFP_WAIT); - rq->flags = REQ_BLOCK_PC; - memset(rq->cmd, 0, sizeof(rq->cmd)); - rq->cmd[0] = GPCMD_START_STOP_UNIT; - rq->cmd[4] = 0x02 + (close != 0); - err = blk_do_rq(q, rq); - blk_put_request(rq); - break; - default: - err = -ENOTTY; - } - - blk_put_queue(q); - return err; -} - -EXPORT_SYMBOL(block_ioctl); diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c Tue Oct 15 20:29:22 2002 +++ b/drivers/block/cciss.c Tue Oct 15 20:29:22 2002 @@ -740,7 +740,7 @@ for(i=0; i< NWD; i++) { struct gendisk *disk = hba[ctlr]->gendisk[i]; - if (disk->part) + if (disk->flags & GENHD_FL_UP) del_gendisk(disk); } @@ -792,7 +792,7 @@ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); /* invalidate the devices and deregister the disk */ - if (disk->part) + if (disk->flags & GENHD_FL_UP) del_gendisk(disk); /* check to see if it was the last disk */ if (logvol == h->highest_lun) { @@ -2274,7 +2274,7 @@ struct gendisk *disk[NWD]; int i, n; for (n = 0; n < NWD; n++) { - disk[n] = alloc_disk(); + disk[n] = alloc_disk(1 << NWD_SHIFT); if (!disk[n]) goto out; } @@ -2447,7 +2447,6 @@ sprintf(disk->disk_name, "cciss/c%dd%d", i, j); disk->major = MAJOR_NR + i; disk->first_minor = j << NWD_SHIFT; - disk->minor_shift = NWD_SHIFT; if( !(drv->nr_blocks)) continue; (BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->block_size; @@ -2500,7 +2499,7 @@ /* remove it from the disk list */ for (j = 0; j < NWD; j++) { struct gendisk *disk = hba[i]->gendisk[j]; - if (disk->part) + if (disk->flags & GENHD_FL_UP) del_gendisk(disk); } diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c --- a/drivers/block/cpqarray.c Tue Oct 15 20:29:12 2002 +++ b/drivers/block/cpqarray.c Tue Oct 15 20:29:12 2002 @@ -304,7 +304,7 @@ kfree(hba[i]->cmd_pool_bits); for (j = 0; j < NWD; j++) { - if (ida_gendisk[i][j]->part) + if (ida_gendisk[i][j]->flags & GENHD_FL_UP) del_gendisk(ida_gendisk[i][j]); put_disk(ida_gendisk[i][j]); } @@ -358,7 +358,7 @@ } num_cntlrs_reg++; for (j=0; jdisk_name, "ida/c%dd%d", i, j); disk->major = MAJOR_NR + i; disk->first_minor = j<minor_shift = NWD_SHIFT; disk->flags = GENHD_FL_DEVFS; disk->fops = &ida_fops; if (!drv->nr_blks) @@ -1428,7 +1427,7 @@ */ for (i = 0; i < NWD; i++) { struct gendisk *disk = ida_gendisk[ctlr][i]; - if (disk->part) + if (disk->flags & GENDH_FL_UP) del_gendisk(disk); } memset(hba[ctlr]->drv, 0, sizeof(drv_info_t)*NWD); diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c --- a/drivers/block/floppy.c Tue Oct 15 20:29:12 2002 +++ b/drivers/block/floppy.c Tue Oct 15 20:29:12 2002 @@ -3488,16 +3488,6 @@ loc.start = 0; return _COPYOUT(loc); } - - case BLKGETSIZE: - ECALL(get_floppy_geometry(drive, type, &g)); - return put_user(g->size, (unsigned long *) param); - - case BLKGETSIZE64: - ECALL(get_floppy_geometry(drive, type, &g)); - return put_user((u64)g->size << 9, (u64 *) param); - /* BLKRRPART is not defined as floppies don't have - * partition tables */ } /* convert the old style command into a new style command */ @@ -4240,7 +4230,7 @@ raw_cmd = NULL; for (i=0; iminor_shift) { - size_t size = sizeof(struct hd_struct)*((1<minor_shift)-1); - p = kmalloc(size, GFP_KERNEL); - if (!p) { - printk(KERN_ERR "out of memory; no partitions for %s\n", - gp->disk_name); - gp->minor_shift = 0; - } else - memset(p, 0, size); - } - gp->part = p; - write_lock(&gendisk_lock); - list_add(&gp->list, &gendisks[gp->major].list); - if (gp->minor_shift) - list_add_tail(&gp->full_list, &gendisk_list); - else - INIT_LIST_HEAD(&gp->full_list); + list_add(&disk->list, &gendisks[disk->major].list); + list_add_tail(&disk->full_list, &gendisk_list); write_unlock(&gendisk_lock); -} - -void add_disk(struct gendisk *disk) -{ - add_gendisk(disk); + disk->flags |= GENHD_FL_UP; register_disk(disk); } @@ -118,6 +97,8 @@ read_lock(&gendisk_lock); if (gendisks[major].get) { disk = gendisks[major].get(minor); + if (disk) + get_disk(disk); read_unlock(&gendisk_lock); return disk; } @@ -125,8 +106,9 @@ disk = list_entry(p, struct gendisk, list); if (disk->first_minor > minor) continue; - if (disk->first_minor + (1<minor_shift) <= minor) + if (disk->first_minor + disk->minors <= minor) continue; + get_disk(disk); read_unlock(&gendisk_lock); *part = minor - disk->first_minor; return disk; @@ -135,8 +117,6 @@ return NULL; } -EXPORT_SYMBOL(get_gendisk); - #ifdef CONFIG_PROC_FS /* iterator */ static void *part_start(struct seq_file *part, loff_t *pos) @@ -173,7 +153,7 @@ seq_puts(part, "major minor #blocks name\n\n"); /* Don't show non-partitionable devices or empty devices */ - if (!get_capacity(sgp)) + if (!get_capacity(sgp) || sgp->minors == 1) return 0; /* show the full disk and all non-0 size partitions of it */ @@ -181,7 +161,7 @@ sgp->major, sgp->first_minor, (unsigned long long)get_capacity(sgp) >> 1, disk_name(sgp, 0, buf)); - for (n = 0; n < (1<minor_shift) - 1; n++) { + for (n = 0; n < sgp->minors - 1; n++) { if (sgp->part[n].nr_sects == 0) continue; seq_printf(part, "%4d %4d %10llu %s\n", @@ -210,6 +190,10 @@ .name = "disk", }; +static struct bus_type disk_bus = { + name: "block", +}; + int __init device_init(void) { int i; @@ -218,6 +202,7 @@ INIT_LIST_HEAD(&gendisks[i].list); blk_dev_init(); devclass_register(&disk_devclass); + bus_register(&disk_bus); return 0; } @@ -225,17 +210,51 @@ EXPORT_SYMBOL(disk_devclass); -struct gendisk *alloc_disk(void) +static void disk_release(struct device *dev) +{ + struct gendisk *disk = dev->driver_data; + kfree(disk->part); + kfree(disk); +} + +struct gendisk *alloc_disk(int minors) { struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL); - if (disk) + if (disk) { memset(disk, 0, sizeof(struct gendisk)); + if (minors > 1) { + int size = (minors - 1) * sizeof(struct hd_struct); + disk->part = kmalloc(size, GFP_KERNEL); + if (!disk->part) { + kfree(disk); + return NULL; + } + memset(disk->part, 0, size); + } + disk->minors = minors; + while (minors >>= 1) + disk->minor_shift++; + INIT_LIST_HEAD(&disk->full_list); + disk->disk_dev.bus = &disk_bus; + disk->disk_dev.release = disk_release; + disk->disk_dev.driver_data = disk; + device_initialize(&disk->disk_dev); + } + return disk; +} + +struct gendisk *get_disk(struct gendisk *disk) +{ + atomic_inc(&disk->disk_dev.refcount); return disk; } void put_disk(struct gendisk *disk) { - kfree(disk); + if (disk) + put_device(&disk->disk_dev); } + EXPORT_SYMBOL(alloc_disk); +EXPORT_SYMBOL(get_disk); EXPORT_SYMBOL(put_disk); diff -Nru a/drivers/block/ioctl.c b/drivers/block/ioctl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/block/ioctl.c Tue Oct 15 20:29:12 2002 @@ -0,0 +1,215 @@ +#include /* for capable() */ +#include /* for set_device_ro() */ +#include +#include +#include +#include + +static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg) +{ + struct block_device *bdevp; + int holder; + struct gendisk *disk; + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + long long start, length; + int part; + int i; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) + return -EFAULT; + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + disk = bdev->bd_disk; + if (bdev != bdev->bd_contains) + return -EINVAL; + part = p.pno; + if (part <= 0 || part >= disk->minors) + return -EINVAL; + switch (a.op) { + case BLKPG_ADD_PARTITION: + start = p.start >> 9; + length = p.length >> 9; + /* check for fit in a hd_struct */ + if (sizeof(sector_t) == sizeof(long) && + sizeof(long long) > sizeof(long)) { + long pstart = start, plength = length; + if (pstart != start || plength != length + || pstart < 0 || plength < 0) + return -EINVAL; + } + /* partition number in use? */ + if (disk->part[part - 1].nr_sects != 0) + return -EBUSY; + /* overlap? */ + for (i = 0; i < disk->minors - 1; i++) { + struct hd_struct *s = &disk->part[i]; + if (!(start+length <= s->start_sect || + start >= s->start_sect + s->nr_sects)) + return -EBUSY; + } + /* all seems OK */ + add_partition(disk, part, start, length); + return 0; + case BLKPG_DEL_PARTITION: + if (disk->part[part - 1].nr_sects == 0) + return -ENXIO; + /* partition in use? Incomplete check for now. */ + bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part); + if (!bdevp) + return -ENOMEM; + if (bd_claim(bdevp, &holder) < 0) { + bdput(bdevp); + return -EBUSY; + } + /* all seems OK */ + fsync_bdev(bdevp); + invalidate_bdev(bdevp, 0); + + delete_partition(disk, part); + bd_release(bdevp); + bdput(bdevp); + return 0; + default: + return -EINVAL; + } +} + +static int blkdev_reread_part(struct block_device *bdev) +{ + struct gendisk *disk = bdev->bd_disk; + int res; + + if (disk->minors == 1 || bdev != bdev->bd_contains) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (down_trylock(&bdev->bd_sem)) + return -EBUSY; + res = rescan_partitions(disk, bdev); + up(&bdev->bd_sem); + return res; +} + +static int put_ushort(unsigned long arg, unsigned short val) +{ + return put_user(val, (unsigned short *)arg); +} + +static int put_int(unsigned long arg, int val) +{ + return put_user(val, (int *)arg); +} + +static int put_long(unsigned long arg, long val) +{ + return put_user(val, (long *)arg); +} + +static int put_ulong(unsigned long arg, unsigned long val) +{ + return put_user(val, (unsigned long *)arg); +} + +static int put_u64(unsigned long arg, u64 val) +{ + return put_user(val, (u64 *)arg); +} + +int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, + unsigned long arg) +{ + struct block_device *bdev = inode->i_bdev; + struct backing_dev_info *bdi; + int holder; + int ret, n; + + switch (cmd) { + case BLKELVGET: + case BLKELVSET: + /* deprecated, use the /proc/iosched interface instead */ + return -ENOTTY; + case BLKRAGET: + case BLKFRAGET: + if (!arg) + return -EINVAL; + bdi = blk_get_backing_dev_info(bdev); + if (bdi == NULL) + return -ENOTTY; + return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512); + case BLKROGET: + return put_int(arg, bdev_read_only(bdev) != 0); + case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */ + return put_int(arg, block_size(bdev)); + case BLKSSZGET: /* get block device hardware sector size */ + return put_int(arg, bdev_hardsect_size(bdev)); + case BLKSECTGET: + return put_ushort(arg, bdev->bd_queue->max_sectors); + case BLKRASET: + case BLKFRASET: + if(!capable(CAP_SYS_ADMIN)) + return -EACCES; + bdi = blk_get_backing_dev_info(bdev); + if (bdi == NULL) + return -ENOTTY; + bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE; + return 0; + case BLKBSZSET: + /* set the logical block size */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (!arg) + return -EINVAL; + if (get_user(n, (int *) arg)) + return -EFAULT; + if (n > PAGE_SIZE || n < 512 || (n & (n - 1))) + return -EINVAL; + if (bd_claim(bdev, &holder) < 0) + return -EBUSY; + set_blocksize(bdev, n); + bd_release(bdev); + return 0; + case BLKPG: + return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg); + case BLKRRPART: + return blkdev_reread_part(bdev); + case BLKGETSIZE: + if ((bdev->bd_inode->i_size >> 9) > ~0UL) + return -EFBIG; + return put_ulong(arg, bdev->bd_inode->i_size >> 9); + case BLKGETSIZE64: + return put_u64(arg, bdev->bd_inode->i_size); + case BLKFLSBUF: + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (bdev->bd_op->ioctl) { + ret = bdev->bd_op->ioctl(inode, file, cmd, arg); + if (ret != -EINVAL) + return ret; + } + fsync_bdev(bdev); + invalidate_bdev(bdev, 0); + return 0; + case BLKROSET: + if (bdev->bd_op->ioctl) { + ret = bdev->bd_op->ioctl(inode, file, cmd, arg); + if (ret != -EINVAL) + return ret; + } + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + if (get_user(n, (int *)(arg))) + return -EFAULT; + set_device_ro(to_kdev_t(bdev->bd_dev), n); + return 0; + default: + if (bdev->bd_op->ioctl) { + ret = bdev->bd_op->ioctl(inode, file, cmd, arg); + if (ret != -EINVAL) + return ret; + } + } + return -ENOTTY; +} diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Tue Oct 15 20:29:12 2002 +++ b/drivers/block/ll_rw_blk.c Tue Oct 15 20:29:12 2002 @@ -1427,7 +1427,19 @@ int rw = rq_data_dir(rq); unsigned int index; - index = disk_index(rq->rq_dev); + if (!rq->rq_disk) + return; + + if (rw == READ) { + rq->rq_disk->rio += new_io; + rq->rq_disk->reads += nr_sectors; + } else if (rw == WRITE) { + rq->rq_disk->wio += new_io; + rq->rq_disk->writes += nr_sectors; + } + + index = rq->rq_disk->first_minor >> rq->rq_disk->minor_shift; + if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) return; @@ -1747,6 +1759,7 @@ req->waiting = NULL; req->bio = req->biotail = bio; req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev); + req->rq_disk = bio->bi_bdev->bd_disk; add_request(q, req, insert_here); out: if (freereq) @@ -1878,7 +1891,7 @@ */ int submit_bio(int rw, struct bio *bio) { - int count = bio_sectors(bio) >> 1; + int count = bio_sectors(bio); BUG_ON(!bio->bi_end_io); BIO_BUG_ON(!bio->bi_size); diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c --- a/drivers/block/loop.c Tue Oct 15 20:29:17 2002 +++ b/drivers/block/loop.c Tue Oct 15 20:29:17 2002 @@ -1075,7 +1075,7 @@ goto out_mem; for (i = 0; i < max_loop; i++) { - disks[i] = alloc_disk(); + disks[i] = alloc_disk(1); if (!disks[i]) goto out_mem2; } diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c --- a/drivers/block/nbd.c Tue Oct 15 20:29:13 2002 +++ b/drivers/block/nbd.c Tue Oct 15 20:29:13 2002 @@ -507,7 +507,7 @@ } for (i = 0; i < MAX_NBD; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); if (!disk) goto out; nbd_dev[i].disk = disk; @@ -537,7 +537,6 @@ nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */ disk->major = MAJOR_NR; disk->first_minor = i; - disk->minor_shift = 0; disk->fops = &nbd_fops; sprintf(disk->disk_name, "nbd%d", i); set_capacity(disk, 0x3ffffe); diff -Nru a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c --- a/drivers/block/paride/pcd.c Tue Oct 15 20:29:16 2002 +++ b/drivers/block/paride/pcd.c Tue Oct 15 20:29:16 2002 @@ -281,7 +281,7 @@ pcd_drive_count = 0; for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); if (!disk) continue; cd->disk = disk; @@ -303,7 +303,6 @@ cd->info.mask = 0; disk->major = major; disk->first_minor = unit; - disk->minor_shift = 0; strcpy(disk->disk_name, cd->name); /* umm... */ disk->fops = &pcd_bdops; } diff -Nru a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c --- a/drivers/block/paride/pd.c Tue Oct 15 20:29:20 2002 +++ b/drivers/block/paride/pd.c Tue Oct 15 20:29:20 2002 @@ -350,9 +350,6 @@ int unit = DEVICE_NR(inode->i_rdev); struct pd_unit *disk = pd + unit; - if (unit >= PD_UNITS || !disk->present) - return -ENODEV; - disk->access++; if (disk->removable) { @@ -703,14 +700,13 @@ } for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) { if (disk->present) { - struct gendisk *p = alloc_disk(); + struct gendisk *p = alloc_disk(1 << PD_BITS); if (!p) { disk->present = 0; k--; continue; } strcpy(p->disk_name, disk->name); - p->minor_shift = PD_BITS; p->fops = &pd_fops; p->major = major; p->first_minor = unit << PD_BITS; diff -Nru a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c --- a/drivers/block/paride/pf.c Tue Oct 15 20:29:18 2002 +++ b/drivers/block/paride/pf.c Tue Oct 15 20:29:18 2002 @@ -308,7 +308,7 @@ pf_drive_count = 0; for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); if (!disk) continue; pf->disk = disk; @@ -320,7 +320,6 @@ disk->major = MAJOR_NR; disk->first_minor = unit; strcpy(disk->disk_name, pf->name); - disk->minor_shift = 0; disk->fops = &pf_fops; if (!(*drives[unit])[D_PRT]) pf_drive_count++; @@ -331,9 +330,6 @@ { int unit = DEVICE_NR(inode->i_rdev); struct pf_unit *pf = units + unit; - - if ((unit >= PF_UNITS) || (!pf->present)) - return -ENODEV; pf_identify(pf); diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c --- a/drivers/block/ps2esdi.c Tue Oct 15 20:29:11 2002 +++ b/drivers/block/ps2esdi.c Tue Oct 15 20:29:11 2002 @@ -89,9 +89,6 @@ static void ps2esdi_normal_interrupt_handler(u_int); static void ps2esdi_initial_reset_int_handler(u_int); static void ps2esdi_geometry_int_handler(u_int); - -static int ps2esdi_open(struct inode *inode, struct file *file); - static int ps2esdi_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg); @@ -141,7 +138,6 @@ static struct block_device_operations ps2esdi_fops = { .owner = THIS_MODULE, - .open = ps2esdi_open, .ioctl = ps2esdi_ioctl, }; @@ -421,13 +417,12 @@ error = -ENOMEM; for (i = 0; i < ps2esdi_drives; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(64); if (!disk) goto err_out4; disk->major = MAJOR_NR; disk->first_minor = i<<6; sprintf(disk->disk_name, "ed%c", 'a'+i); - disk->minor_shift = 6; disk->fops = &ps2esdi_fops; ps2esdi_gendisk[i] = disk; } @@ -1074,15 +1069,6 @@ #undef WAIT_FOR_STATUS -} - - -static int ps2esdi_open(struct inode *inode, struct file *file) -{ - int dev = DEVICE_NR(inode->i_rdev); - if (dev >= ps2esdi_drives) - return -ENODEV; - return 0; } static int ps2esdi_ioctl(struct inode *inode, diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c --- a/drivers/block/rd.c Tue Oct 15 20:29:17 2002 +++ b/drivers/block/rd.c Tue Oct 15 20:29:17 2002 @@ -291,8 +291,6 @@ if (cmd != BLKFLSBUF) return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; /* special: we want to release the ramdisk memory, it's not like with the other blockdevices where this ioctl only flushes away the buffer cache. */ @@ -383,6 +381,7 @@ rd_bdev[unit]->bd_inode->i_mapping->a_ops = &ramdisk_aops; rd_bdev[unit]->bd_inode->i_size = rd_length[unit]; rd_bdev[unit]->bd_queue = &blk_dev[MAJOR_NR].request_queue; + rd_bdev[unit]->bd_disk = get_disk(rd_disks[unit]); } return 0; @@ -431,17 +430,16 @@ } #ifdef CONFIG_BLK_DEV_INITRD - initrd_disk = alloc_disk(); + initrd_disk = alloc_disk(1); if (!initrd_disk) return -ENOMEM; initrd_disk->major = MAJOR_NR; initrd_disk->first_minor = INITRD_MINOR; - initrd_disk->minor_shift = 0; initrd_disk->fops = &rd_bd_op; sprintf(initrd_disk->disk_name, "initrd"); #endif for (i = 0; i < NUM_RAMDISKS; i++) { - rd_disks[i] = alloc_disk(); + rd_disks[i] = alloc_disk(1); if (!rd_disks[i]) goto out; } @@ -460,7 +458,6 @@ rd_length[i] = rd_size << 10; disk->major = MAJOR_NR; disk->first_minor = i; - disk->minor_shift = 0; disk->fops = &rd_bd_op; sprintf(disk->disk_name, "rd%d", i); set_capacity(disk, rd_size * 2); diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/block/scsi_ioctl.c Tue Oct 15 20:29:23 2002 @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2001 Jens Axboe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public Licens + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +int blk_do_rq(request_queue_t *q, struct request *rq) +{ + DECLARE_COMPLETION(wait); + int err = 0; + + rq->flags |= REQ_NOMERGE; + rq->waiting = &wait; + elv_add_request(q, rq, 1); + generic_unplug_device(q); + wait_for_completion(&wait); + + /* + * for now, never retry anything + */ + if (rq->errors) + err = -EIO; + + return err; +} + +#include + +static int sg_get_version(int *p) +{ + static int sg_version_num = 30527; + return put_user(sg_version_num, p); +} + +static int scsi_get_idlun(request_queue_t *q, int *p) +{ + return put_user(0, p); +} + +static int scsi_get_bus(request_queue_t *q, int *p) +{ + return put_user(0, p); +} + +static int sg_get_timeout(request_queue_t *q) +{ + return HZ; +} + +static int sg_set_timeout(request_queue_t *q, int *p) +{ + int timeout; + int error = get_user(timeout, p); + return error; +} + +static int reserved_size = 0; + +static int sg_get_reserved_size(request_queue_t *q, int *p) +{ + return put_user(reserved_size, p); +} + +static int sg_set_reserved_size(request_queue_t *q, int *p) +{ + int size; + int error = get_user(size, p); + if (!error) + reserved_size = size; + return error; +} + +static int sg_emulated_host(request_queue_t *q, int *p) +{ + return put_user(1, p); +} + +static int sg_io(request_queue_t *q, struct sg_io_hdr *uptr) +{ + int err; + struct sg_io_hdr hdr; + struct request *rq; + void *buffer; + + if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr))) + return -EFAULT; + if (copy_from_user(&hdr, uptr, sizeof(*uptr))) + return -EFAULT; + + if ( hdr.cmd_len > sizeof(rq->cmd) ) + return -EINVAL; + + buffer = NULL; + if (hdr.dxfer_len) { + unsigned int bytes = (hdr.dxfer_len + 511) & ~511; + + switch (hdr.dxfer_direction) { + default: + return -EINVAL; + case SG_DXFER_TO_DEV: + case SG_DXFER_FROM_DEV: + case SG_DXFER_TO_FROM_DEV: + break; + } + buffer = kmalloc(bytes, GFP_USER); + if (!buffer) + return -ENOMEM; + if (hdr.dxfer_direction == SG_DXFER_TO_DEV || + hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV) + copy_from_user(buffer, hdr.dxferp, hdr.dxfer_len); + } + + rq = blk_get_request(q, WRITE, __GFP_WAIT); + rq->timeout = 60*HZ; + rq->data = buffer; + rq->data_len = hdr.dxfer_len; + rq->flags = REQ_BLOCK_PC; + memset(rq->cmd, 0, sizeof(rq->cmd)); + copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len); + err = blk_do_rq(q, rq); + + blk_put_request(rq); + + copy_to_user(uptr, &hdr, sizeof(*uptr)); + if (buffer) { + if (hdr.dxfer_direction == SG_DXFER_FROM_DEV || + hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV) + copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len); + kfree(buffer); + } + return err; +} + +int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) +{ + request_queue_t *q; + struct request *rq; + int close = 0, err; + + q = bdev_get_queue(bdev); + if (!q) + return -ENXIO; + + switch (cmd) { + case SG_GET_VERSION_NUM: + return sg_get_version((int *) arg); + case SCSI_IOCTL_GET_IDLUN: + return scsi_get_idlun(q, (int *) arg); + case SCSI_IOCTL_GET_BUS_NUMBER: + return scsi_get_bus(q, (int *) arg); + case SG_SET_TIMEOUT: + return sg_set_timeout(q, (int *) arg); + case SG_GET_TIMEOUT: + return sg_get_timeout(q); + case SG_GET_RESERVED_SIZE: + return sg_get_reserved_size(q, (int *) arg); + case SG_SET_RESERVED_SIZE: + return sg_set_reserved_size(q, (int *) arg); + case SG_EMULATED_HOST: + return sg_emulated_host(q, (int *) arg); + case SG_IO: + return sg_io(q, (struct sg_io_hdr *) arg); + case CDROMCLOSETRAY: + close = 1; + case CDROMEJECT: + rq = blk_get_request(q, WRITE, __GFP_WAIT); + rq->flags = REQ_BLOCK_PC; + rq->data = NULL; + rq->data_len = 0; + rq->timeout = 60*HZ; + memset(rq->cmd, 0, sizeof(rq->cmd)); + rq->cmd[0] = GPCMD_START_STOP_UNIT; + rq->cmd[4] = 0x02 + (close != 0); + err = blk_do_rq(q, rq); + blk_put_request(rq); + break; + default: + err = -ENOTTY; + } + + blk_put_queue(q); + return err; +} + +EXPORT_SYMBOL(scsi_cmd_ioctl); diff -Nru a/drivers/block/swim3.c b/drivers/block/swim3.c --- a/drivers/block/swim3.c Tue Oct 15 20:29:16 2002 +++ b/drivers/block/swim3.c Tue Oct 15 20:29:16 2002 @@ -1037,7 +1037,7 @@ return -ENODEV; for (i = 0; i < floppy_count; i++) { - disks[i] = alloc_disk(); + disks[i] = alloc_disk(1); if (!disks[i]) goto out; } diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c --- a/drivers/block/swim_iop.c Tue Oct 15 20:29:11 2002 +++ b/drivers/block/swim_iop.c Tue Oct 15 20:29:11 2002 @@ -188,7 +188,7 @@ printk("SWIM-IOP: detected %d installed drives.\n", floppy_count); for (i = 0; i < floppy_count; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); if (!disk) continue; disk->major = MAJOR_NR; diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c --- a/drivers/block/umem.c Tue Oct 15 20:29:23 2002 +++ b/drivers/block/umem.c Tue Oct 15 20:29:23 2002 @@ -864,18 +864,6 @@ return 0; } - -/* ------------------------------------------------------------------------------------ --- mm_open ------------------------------------------------------------------------------------ -*/ -static int mm_open(struct inode *i, struct file *filp) -{ - if (DEVICE_NR(i->i_rdev) >= num_cards) - return -ENXIO; - return 0; -} /* ----------------------------------------------------------------------------------- -- mm_fops @@ -883,7 +871,6 @@ */ static struct block_device_operations mm_fops = { owner: THIS_MODULE, - open: mm_open, ioctl: mm_ioctl, revalidate: mm_revalidate, check_media_change: mm_check_change, @@ -1190,7 +1177,7 @@ } for (i = 0; i < num_cards; i++) { - mm_gendisk[i] = alloc_disk(); + mm_gendisk[i] = alloc_disk(1 << MM_SHIFT); if (!mm_gendisk[i]) goto out; } @@ -1203,7 +1190,6 @@ spin_lock_init(&cards[i].lock); disk->major = major_nr; disk->first_minor = i << MM_SHIFT; - disk->minor_shift = MM_SHIFT; disk->fops = &mm_fops; set_capacity(disk, cards[i].mm_size << 1); add_disk(disk); diff -Nru a/drivers/block/xd.c b/drivers/block/xd.c --- a/drivers/block/xd.c Tue Oct 15 20:29:20 2002 +++ b/drivers/block/xd.c Tue Oct 15 20:29:20 2002 @@ -130,7 +130,6 @@ static struct block_device_operations xd_fops = { owner: THIS_MODULE, - open: xd_open, ioctl: xd_ioctl, }; static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); @@ -205,12 +204,11 @@ goto out3; for (i = 0; i < xd_drives; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(64); if (!disk) goto Enomem; disk->major = MAJOR_NR; disk->first_minor = i<<6; - disk->minor_shift = 6; sprintf(disk->disk_name, "xd%c", i+'a'); disk->fops = &xd_fops; xd_gendisk[i] = disk; @@ -284,15 +282,6 @@ return (found); } -/* xd_open: open a device */ -static int xd_open (struct inode *inode,struct file *file) -{ - int dev = DEVICE_NR(inode->i_rdev); - if (dev >= xd_drives) - return -ENXIO; - return 0; -} - /* do_xd_request: handle an incoming request */ static void do_xd_request (request_queue_t * q) { @@ -337,8 +326,6 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) { int dev = DEVICE_NR(inode->i_rdev); - - if (dev >= xd_drives) return -EINVAL; switch (cmd) { case HDIO_GETGEO: { diff -Nru a/drivers/block/z2ram.c b/drivers/block/z2ram.c --- a/drivers/block/z2ram.c Tue Oct 15 20:29:17 2002 +++ b/drivers/block/z2ram.c Tue Oct 15 20:29:17 2002 @@ -365,14 +365,13 @@ MAJOR_NR ); return -EBUSY; } - z2ram_gendisk = alloc_disk(); + z2ram_gendisk = alloc_disk(1); if (!z2ram_gendisk) { unregister_blkdev( MAJOR_NR, DEVICE_NAME ); return -ENOMEM; } z2ram_gendisk->major = MAJOR_NR; z2ram_gendisk->first_minor = 0; - z2ram_gendisk->minor_shift = 0; z2ram_gendisk->fops = &z2_fops; sprintf(z2ram_gendisk->disk_name, "z2ram"); diff -Nru a/drivers/bluetooth/Config.help b/drivers/bluetooth/Config.help --- a/drivers/bluetooth/Config.help Tue Oct 15 20:29:16 2002 +++ b/drivers/bluetooth/Config.help Tue Oct 15 20:29:16 2002 @@ -1,5 +1,5 @@ HCI UART driver -CONFIG_BLUEZ_HCIUART +CONFIG_BT_HCIUART Bluetooth HCI UART driver. This driver is required if you want to use Bluetooth devices with serial port interface. You will also need this driver if you have @@ -10,7 +10,7 @@ kernel or say M to compile it as module (hci_uart.o). HCI UART (H4) protocol support -CONFIG_BLUEZ_HCIUART_H4 +CONFIG_BT_HCIUART_H4 UART (H4) is serial protocol for communication between Bluetooth device and host. This protocol is required for most Bluetooth devices with UART interface, including PCMCIA and CF cards. @@ -18,7 +18,7 @@ Say Y here to compile support for HCI UART (H4) protocol. HCI BCSP protocol support -CONFIG_BLUEZ_HCIUART_BCSP +CONFIG_BT_HCIUART_BCSP BCSP (BlueCore Serial Protocol) is serial protocol for communication between Bluetooth device and host. This protocol is required for non USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and @@ -27,7 +27,7 @@ Say Y here to compile support for HCI BCSP protocol. HCI USB driver -CONFIG_BLUEZ_HCIUSB +CONFIG_BT_HCIUSB Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with USB interface. @@ -36,7 +36,7 @@ kernel or say M to compile it as module (hci_usb.o). HCI USB zero packet support -CONFIG_BLUEZ_USB_ZERO_PACKET +CONFIG_BT_USB_ZERO_PACKET Support for USB zero packets. This option is provided only as a work around for buggy Bluetooth USB devices. Do _not_ enable it unless you know for sure that your device @@ -44,7 +44,7 @@ Most people should say N here. HCI VHCI Virtual HCI device driver -CONFIG_BLUEZ_HCIVHCI +CONFIG_BT_HCIVHCI Bluetooth Virtual HCI device driver. This driver is required if you want to use HCI Emulation software. @@ -52,7 +52,7 @@ kernel or say M to compile it as module (hci_vhci.o). HCI DTL1 (PC Card) device driver -CONFIG_BLUEZ_HCIDTL1 +CONFIG_BT_HCIDTL1 Bluetooth HCI DTL1 (PC Card) driver. This driver provides support for Bluetooth PCMCIA devices with Nokia DTL1 interface: @@ -63,7 +63,7 @@ kernel or say M to compile it as module (dtl1_cs.o). HCI BT3C (PC Card) device driver -CONFIG_BLUEZ_HCIBT3C +CONFIG_BT_HCIBT3C Bluetooth HCI BT3C (PC Card) driver. This driver provides support for Bluetooth PCMCIA devices with 3Com BT3C interface: @@ -77,7 +77,7 @@ kernel or say M to compile it as module (bt3c_cs.o). HCI BlueCard (PC Card) device driver -CONFIG_BLUEZ_HCIBLUECARD +CONFIG_BT_HCIBLUECARD Bluetooth HCI BlueCard (PC Card) driver. This driver provides support for Bluetooth PCMCIA devices with Anycom BlueCard interface: diff -Nru a/drivers/bluetooth/Config.in b/drivers/bluetooth/Config.in --- a/drivers/bluetooth/Config.in Tue Oct 15 20:29:17 2002 +++ b/drivers/bluetooth/Config.in Tue Oct 15 20:29:17 2002 @@ -1,23 +1,23 @@ mainmenu_option next_comment comment 'Bluetooth device drivers' -dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB -if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then - bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET +dep_tristate 'HCI USB driver' CONFIG_BT_HCIUSB $CONFIG_BT $CONFIG_USB +if [ "$CONFIG_BT_HCIUSB" != "n" ]; then + bool ' USB zero packet support' CONFIG_BT_USB_ZERO_PACKET fi -dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ -if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then - bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4 - bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP +dep_tristate 'HCI UART driver' CONFIG_BT_HCIUART $CONFIG_BT +if [ "$CONFIG_BT_HCIUART" != "n" ]; then + bool ' UART (H4) protocol support' CONFIG_BT_HCIUART_H4 + bool ' BCSP protocol support' CONFIG_BT_HCIUART_BCSP fi -dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ +dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BT_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BT -dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ +dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BT_HCIBT3C $CONFIG_PCMCIA $CONFIG_BT -dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ +dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BT_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BT -dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ +dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BT_HCIVHCI $CONFIG_BT endmenu diff -Nru a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile --- a/drivers/bluetooth/Makefile Tue Oct 15 20:29:22 2002 +++ b/drivers/bluetooth/Makefile Tue Oct 15 20:29:22 2002 @@ -2,16 +2,16 @@ # Makefile for the Linux Bluetooth HCI device drivers. # -obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o -obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o -obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o -obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o -obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o -obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o +obj-$(CONFIG_BT_HCIUSB) += hci_usb.o +obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o +obj-$(CONFIG_BT_HCIUART) += hci_uart.o +obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o +obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o +obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o hci_uart-y := hci_ldisc.o -hci_uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o -hci_uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o +hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o +hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-objs := $(hci_uart-y) include $(TOPDIR)/Rules.make diff -Nru a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c --- a/drivers/bluetooth/bluecard_cs.c Tue Oct 15 20:29:17 2002 +++ b/drivers/bluetooth/bluecard_cs.c Tue Oct 15 20:29:17 2002 @@ -60,7 +60,7 @@ MODULE_PARM(irq_list, "1-4i"); MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)"); +MODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)"); MODULE_LICENSE("GPL"); @@ -396,7 +396,7 @@ if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; - if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); return; } @@ -571,7 +571,7 @@ /* Ericsson baud rate command */ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; - if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + if (!(skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n"); return -1; } diff -Nru a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c --- a/drivers/bluetooth/bt3c_cs.c Tue Oct 15 20:29:23 2002 +++ b/drivers/bluetooth/bt3c_cs.c Tue Oct 15 20:29:23 2002 @@ -72,7 +72,7 @@ MODULE_PARM(irq_list, "1-4i"); MODULE_AUTHOR("Marcel Holtmann , Jose Orlando Pereira "); -MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card"); +MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card"); MODULE_LICENSE("GPL"); @@ -264,7 +264,7 @@ if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; - if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n"); return; } diff -Nru a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c --- a/drivers/bluetooth/dtl1_cs.c Tue Oct 15 20:29:16 2002 +++ b/drivers/bluetooth/dtl1_cs.c Tue Oct 15 20:29:16 2002 @@ -66,7 +66,7 @@ MODULE_PARM(irq_list, "1-4i"); MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1"); +MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1"); MODULE_LICENSE("GPL"); @@ -238,7 +238,7 @@ /* Allocate packet */ if (info->rx_skb == NULL) - if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); info->rx_state = RECV_WAIT_NSH; info->rx_count = NSHL; @@ -433,7 +433,7 @@ nsh.zero = 0; nsh.len = skb->len; - s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); + s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); skb_reserve(s, NSHL); memcpy(skb_put(s, skb->len), skb->data, skb->len); if (skb->len & 0x0001) diff -Nru a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c --- a/drivers/bluetooth/hci_bcsp.c Tue Oct 15 20:29:21 2002 +++ b/drivers/bluetooth/hci_bcsp.c Tue Oct 15 20:29:21 2002 @@ -57,7 +57,7 @@ #include "hci_uart.h" #include "hci_bcsp.h" -#ifndef HCI_UART_DEBUG +#ifndef CONFIG_BT_HCIUART_DEBUG #undef BT_DBG #define BT_DBG( A... ) #undef BT_DMP @@ -176,7 +176,7 @@ u8 hdr[4], chan; int rel, i; -#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC +#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC u16 BCSP_CRC_INIT(bcsp_txmsg_crc); #endif @@ -228,7 +228,7 @@ BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; } -#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC +#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC hdr[0] |= 0x40; #endif @@ -240,7 +240,7 @@ /* Put BCSP header */ for (i = 0; i < 4; i++) { bcsp_slip_one_byte(nskb, hdr[i]); -#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC +#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); #endif } @@ -248,12 +248,12 @@ /* Put payload */ for (i = 0; i < len; i++) { bcsp_slip_one_byte(nskb, data[i]); -#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC +#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC bcsp_crc_update(&bcsp_txmsg_crc, data[i]); #endif } -#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC +#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC /* Put CRC */ bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); @@ -611,7 +611,7 @@ * Allocate packet. Max len of a BCSP pkt= * 0xFFF (payload) +4 (header) +2 (crc) */ - bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC); + bcsp->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC); if (!bcsp->rx_skb) { BT_ERR("Can't allocate mem for new packet"); bcsp->rx_state = BCSP_W4_PKT_DELIMITER; diff -Nru a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c --- a/drivers/bluetooth/hci_h4.c Tue Oct 15 20:29:16 2002 +++ b/drivers/bluetooth/hci_h4.c Tue Oct 15 20:29:16 2002 @@ -23,7 +23,7 @@ */ /* - * BlueZ HCI UART(H4) protocol. + * Bluetooth HCI UART(H4) protocol. * * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $ */ @@ -56,7 +56,7 @@ #include "hci_uart.h" #include "hci_h4.h" -#ifndef HCI_UART_DEBUG +#ifndef CONFIG_BT_HCIUART_DEBUG #undef BT_DBG #define BT_DBG( A... ) #undef BT_DMP @@ -160,7 +160,7 @@ ptr = data; while (count) { if (h4->rx_count) { - len = MIN(h4->rx_count, count); + len = min_t(unsigned int, h4->rx_count, count); memcpy(skb_put(h4->rx_skb, len), ptr, len); h4->rx_count -= len; count -= len; ptr += len; @@ -238,7 +238,7 @@ ptr++; count--; /* Allocate packet */ - h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); if (!h4->rx_skb) { BT_ERR("Can't allocate mem for new packet"); h4->rx_state = H4_W4_PACKET_TYPE; diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c --- a/drivers/bluetooth/hci_ldisc.c Tue Oct 15 20:29:20 2002 +++ b/drivers/bluetooth/hci_ldisc.c Tue Oct 15 20:29:20 2002 @@ -23,7 +23,7 @@ */ /* - * BlueZ HCI UART driver. + * Bluetooth HCI UART driver. * * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $ */ @@ -55,7 +55,7 @@ #include #include "hci_uart.h" -#ifndef HCI_UART_DEBUG +#ifndef CONFIG_BT_HCIUART_DEBUG #undef BT_DBG #define BT_DBG( A... ) #undef BT_DMP @@ -507,11 +507,11 @@ return 0; } -#ifdef CONFIG_BLUEZ_HCIUART_H4 +#ifdef CONFIG_BT_HCIUART_H4 int h4_init(void); int h4_deinit(void); #endif -#ifdef CONFIG_BLUEZ_HCIUART_BCSP +#ifdef CONFIG_BT_HCIUART_BCSP int bcsp_init(void); int bcsp_deinit(void); #endif @@ -521,7 +521,7 @@ static struct tty_ldisc hci_uart_ldisc; int err; - BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + BT_INFO("Bluetooth HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); @@ -545,10 +545,10 @@ return err; } -#ifdef CONFIG_BLUEZ_HCIUART_H4 +#ifdef CONFIG_BT_HCIUART_H4 h4_init(); #endif -#ifdef CONFIG_BLUEZ_HCIUART_BCSP +#ifdef CONFIG_BT_HCIUART_BCSP bcsp_init(); #endif @@ -559,10 +559,10 @@ { int err; -#ifdef CONFIG_BLUEZ_HCIUART_H4 +#ifdef CONFIG_BT_HCIUART_H4 h4_deinit(); #endif -#ifdef CONFIG_BLUEZ_HCIUART_BCSP +#ifdef CONFIG_BT_HCIUART_BCSP bcsp_deinit(); #endif @@ -575,5 +575,5 @@ module_exit(hci_uart_cleanup); MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); +MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION); MODULE_LICENSE("GPL"); diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c Tue Oct 15 20:29:21 2002 +++ b/drivers/bluetooth/hci_usb.c Tue Oct 15 20:29:21 2002 @@ -23,7 +23,7 @@ */ /* - * BlueZ HCI USB driver. + * Bluetooth HCI USB driver. * Based on original USB Bluetooth driver for Linux kernel * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner @@ -59,14 +59,14 @@ #define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1) -#ifndef HCI_USB_DEBUG +#ifndef CONFIG_BT_HCIUSB_DEBUG #undef BT_DBG #define BT_DBG( A... ) #undef BT_DMP #define BT_DMP( A... ) #endif -#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET +#ifndef CONFIG_BT_USB_ZERO_PACKET #undef USB_ZERO_PACKET #define USB_ZERO_PACKET 0 #endif @@ -167,7 +167,7 @@ size = HCI_MAX_FRAME_SIZE; - if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) { + if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) { usb_free_urb(urb); return -ENOMEM; } @@ -465,7 +465,7 @@ if (count > len) goto bad_len; - skb = bluez_skb_alloc(len, GFP_ATOMIC); + skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) { BT_ERR("%s no memory for event packet", husb->hdev.name); goto done; @@ -569,7 +569,7 @@ if (count != size) { BT_ERR("%s corrupted ACL packet: count %d, dlen %d", husb->hdev.name, count, dlen); - bluez_dump("hci_usb", skb->data, count); + bt_dump("hci_usb", skb->data, count); husb->hdev.stat.err_rx++; goto resubmit; } @@ -639,7 +639,7 @@ /* Find endpoints that we need */ - ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM); + ifn = min_t(unsigned int, udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM); for (i = 0; i < ifn; i++) { iface = &udev->actconfig->interface[i]; for (a = 0; a < iface->num_altsetting; a++) { @@ -781,7 +781,7 @@ { int err; - BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + BT_INFO("Bluetooth HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); @@ -800,5 +800,5 @@ module_exit(hci_usb_cleanup); MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION); +MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); MODULE_LICENSE("GPL"); diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c --- a/drivers/bluetooth/hci_vhci.c Tue Oct 15 20:29:22 2002 +++ b/drivers/bluetooth/hci_vhci.c Tue Oct 15 20:29:22 2002 @@ -23,7 +23,7 @@ */ /* - * BlueZ HCI virtual device driver. + * Bluetooth HCI virtual device driver. * * $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $ */ @@ -136,7 +136,7 @@ if (count > HCI_MAX_FRAME_SIZE) return -EINVAL; - if (!(skb = bluez_skb_alloc(count, GFP_KERNEL))) + if (!(skb = bt_skb_alloc(count, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(skb_put(skb, count), buf, count)) { @@ -172,7 +172,7 @@ int len = count, total = 0; char *ptr = buf; - len = MIN(skb->len, len); + len = min_t(unsigned int, skb->len, len); if (copy_to_user(ptr, skb->data, len)) return -EFAULT; total += len; @@ -331,7 +331,7 @@ int __init hci_vhci_init(void) { - BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", + BT_INFO("Bluetooth VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION); BT_INFO("Written 2000,2001 by Maxim Krasnyansky "); @@ -352,5 +352,5 @@ module_exit(hci_vhci_cleanup); MODULE_AUTHOR("Maxim Krasnyansky "); -MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION); +MODULE_DESCRIPTION("Bluetooth VHCI driver ver " VERSION); MODULE_LICENSE("GPL"); diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c --- a/drivers/cdrom/aztcd.c Tue Oct 15 20:29:21 2002 +++ b/drivers/cdrom/aztcd.c Tue Oct 15 20:29:21 2002 @@ -1908,7 +1908,7 @@ } devfs_register(NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL); - azt_disk = alloc_disk(); + azt_disk = alloc_disk(1); if (!azt_disk) goto err_out2; if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0) { @@ -1921,7 +1921,6 @@ blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048); azt_disk->major = MAJOR_NR; azt_disk->first_minor = 0; - azt_disk->minor_shift = 0; azt_disk->fops = &azt_fops; sprintf(azt_disk->disk_name, "aztcd"); add_disk(azt_disk); diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c --- a/drivers/cdrom/cdrom.c Tue Oct 15 20:29:12 2002 +++ b/drivers/cdrom/cdrom.c Tue Oct 15 20:29:12 2002 @@ -443,15 +443,16 @@ if ((cdi = cdrom_find_device(dev)) == NULL) return -ENODEV; - if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM)) - return -EROFS; - /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) ret = cdi->ops->open(cdi, 1); - else + else { + if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM)) + return -EROFS; + ret = open_for_data(cdi); + } if (!ret) cdi->use_count++; diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c --- a/drivers/cdrom/cdu31a.c Tue Oct 15 20:29:12 2002 +++ b/drivers/cdrom/cdu31a.c Tue Oct 15 20:29:12 2002 @@ -3366,12 +3366,11 @@ goto errout2; } - disk = alloc_disk(); + disk = alloc_disk(1); if (!disk) goto errout1; disk->major = MAJOR_NR; disk->first_minor = 0; - disk->minor_shift = 0; sprintf(disk->disk_name, "cdu31a"); disk->fops = &scd_bdops; disk->flags = GENHD_FL_CD; diff -Nru a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c --- a/drivers/cdrom/cm206.c Tue Oct 15 20:29:21 2002 +++ b/drivers/cdrom/cm206.c Tue Oct 15 20:29:21 2002 @@ -1470,12 +1470,11 @@ printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR); goto out_blkdev; } - disk = alloc_disk(); + disk = alloc_disk(1); if (!disk) goto out_disk; disk->major = MAJOR_NR; disk->first_minor = 0; - disk->minor_shift = 0; sprintf(disk->disk_name, "cm206"); disk->fops = &cm206_bdops; disk->flags = GENHD_FL_CD; diff -Nru a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c --- a/drivers/cdrom/gscd.c Tue Oct 15 20:29:11 2002 +++ b/drivers/cdrom/gscd.c Tue Oct 15 20:29:11 2002 @@ -972,12 +972,11 @@ i++; } - gscd_disk = alloc_disk(); + gscd_disk = alloc_disk(1); if (!gscd_disk) goto err_out1; gscd_disk->major = MAJOR_NR; gscd_disk->first_minor = 0; - gscd_disk->minor_shift = 0; gscd_disk->fops = &gscd_fops; sprintf(gscd_disk->disk_name, "gscd"); diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c --- a/drivers/cdrom/mcd.c Tue Oct 15 20:29:17 2002 +++ b/drivers/cdrom/mcd.c Tue Oct 15 20:29:17 2002 @@ -1031,7 +1031,7 @@ int __init mcd_init(void) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); int count; unsigned char result[3]; char msg[80]; @@ -1124,7 +1124,6 @@ disk->major = MAJOR_NR; disk->first_minor = 0; - disk->minor_shift = 0; sprintf(disk->disk_name, "mcd"); disk->fops = &mcd_bdops; disk->flags = GENHD_FL_CD; diff -Nru a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c --- a/drivers/cdrom/mcdx.c Tue Oct 15 20:29:16 2002 +++ b/drivers/cdrom/mcdx.c Tue Oct 15 20:29:16 2002 @@ -1076,7 +1076,7 @@ return 1; } - disk = alloc_disk(); + disk = alloc_disk(1); if (!disk) { xwarn("init() malloc failed\n"); kfree(stuffp); @@ -1221,7 +1221,6 @@ stuffp->info.dev = mk_kdev(MAJOR_NR, drive); disk->major = MAJOR_NR; disk->first_minor = drive; - disk->minor_shift = 0; strcpy(disk->disk_name, stuffp->info.name); disk->fops = &mcdx_bdops; disk->flags = GENHD_FL_CD; diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c --- a/drivers/cdrom/optcd.c Tue Oct 15 20:29:14 2002 +++ b/drivers/cdrom/optcd.c Tue Oct 15 20:29:14 2002 @@ -2010,14 +2010,13 @@ "optcd: no Optics Storage CDROM Initialization\n"); return -EIO; } - optcd_disk = alloc_disk(); + optcd_disk = alloc_disk(1); if (!optcd_disk) { printk(KERN_ERR "optcd: can't allocate disk\n"); return -ENOMEM; } optcd_disk->major = MAJOR_NR; optcd_disk->first_minor = 0; - optcd_disk->minor_shift = 0; optcd_disk->fops = &opt_fops; sprintf(optcd_disk->disk_name, "optcd"); if (!request_region(optcd_port, 4, "optcd")) { diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c --- a/drivers/cdrom/sbpcd.c Tue Oct 15 20:29:12 2002 +++ b/drivers/cdrom/sbpcd.c Tue Oct 15 20:29:12 2002 @@ -5831,10 +5831,9 @@ sbpcd_infop->dev = mk_kdev(MAJOR_NR, j); sbpcd_infop->handle = p; p->sbpcd_infop = sbpcd_infop; - disk = alloc_disk(); + disk = alloc_disk(1); disk->major = MAJOR_NR; disk->first_minor = j; - disk->minor_shift = 0; disk->fops = &sbpcd_bdops; strcpy(disk->disk_name, sbpcd_infop->name); disk->flags = GENHD_FL_CD; diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c --- a/drivers/cdrom/sjcd.c Tue Oct 15 20:29:17 2002 +++ b/drivers/cdrom/sjcd.c Tue Oct 15 20:29:17 2002 @@ -1689,14 +1689,13 @@ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sjcd_request, &sjcd_lock); blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048); - sjcd_disk = alloc_disk(); + sjcd_disk = alloc_disk(1); if (!sjcd_disk) { printk(KERN_ERR "SJCD: can't allocate disk"); goto out1; } sjcd_disk->major = MAJOR_NR, sjcd_disk->first_minor = 0, - sjcd_disk->minor_shift = 0, sjcd_disk->fops = &sjcd_fops, sprintf(sjcd_disk->disk_name, "sjcd"); diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c --- a/drivers/cdrom/sonycd535.c Tue Oct 15 20:29:16 2002 +++ b/drivers/cdrom/sonycd535.c Tue Oct 15 20:29:16 2002 @@ -1605,12 +1605,11 @@ } initialized = 1; - cdu_disk = alloc_disk(); + cdu_disk = alloc_disk(1); if (!cdu_disk) goto out6; cdu_disk->major = MAJOR_NR; cdu_disk->first_minor = 0; - cdu_disk->minor_shift = 0; cdu_disk->fops = &cdu_fops; sprintf(cdu_disk->disk_name, "cdu"); diff -Nru a/drivers/char/Config.help b/drivers/char/Config.help --- a/drivers/char/Config.help Tue Oct 15 20:29:16 2002 +++ b/drivers/char/Config.help Tue Oct 15 20:29:16 2002 @@ -1033,3 +1033,24 @@ If compiled as a module, it will be called scx200_gpio.o. +Texas Instruments parallel link cable support +CONFIG_TIPAR + If you own a Texas Instruments graphing calculator and use a + parallel link cable, then you might be interested in this driver. + + If you enable this driver, you will be able to communicate with + your calculator through a set of device nodes under /dev. The + main advantage of this driver is that you don't have to be root + to use this precise link cable (depending on the permissions on + the device nodes, though). + + 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 tipar.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt. + + If you don't know what a parallel link cable is or what a Texas + Instruments graphing calculator is, then you probably don't need this + driver. + + If unsure, say N. \ No newline at end of file diff -Nru a/drivers/char/Config.in b/drivers/char/Config.in --- a/drivers/char/Config.in Tue Oct 15 20:29:12 2002 +++ b/drivers/char/Config.in Tue Oct 15 20:29:12 2002 @@ -80,6 +80,7 @@ bool ' Support for console on line printer' CONFIG_LP_CONSOLE fi dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT + dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT fi if [ "$CONFIG_PPC_PSERIES" = "y" ]; then bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile --- a/drivers/char/Makefile Tue Oct 15 20:29:22 2002 +++ b/drivers/char/Makefile Tue Oct 15 20:29:22 2002 @@ -50,6 +50,7 @@ obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_PRINTER) += lp.o +obj-$(CONFIG_TIPAR) += tipar.o obj-$(CONFIG_BUSMOUSE) += busmouse.o obj-$(CONFIG_DTLK) += dtlk.o diff -Nru a/drivers/char/drm/drm_ioctl.h b/drivers/char/drm/drm_ioctl.h --- a/drivers/char/drm/drm_ioctl.h Tue Oct 15 20:29:14 2002 +++ b/drivers/char/drm/drm_ioctl.h Tue Oct 15 20:29:14 2002 @@ -32,6 +32,7 @@ #define __NO_VERSION__ #include "drmP.h" + int DRM(irq_busid)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -41,8 +42,20 @@ if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p))) return -EFAULT; dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); - if (dev) p.irq = dev->irq; - else p.irq = 0; + if (!dev) { + DRM_ERROR("pci_find_slot failed for %d:%d:%d\n", + p.busnum, p.devnum, p.funcnum); + p.irq = 0; + goto out; + } + if (pci_enable_device(dev) != 0) { + DRM_ERROR("pci_enable_device failed for %d:%d:%d\n", + p.busnum, p.devnum, p.funcnum); + p.irq = 0; + goto out; + } + p.irq = dev->irq; + out: DRM_DEBUG("%d:%d:%d => IRQ %d\n", p.busnum, p.devnum, p.funcnum, p.irq); if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p))) diff -Nru a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h --- a/drivers/char/drm/drm_os_linux.h Tue Oct 15 20:29:16 2002 +++ b/drivers/char/drm/drm_os_linux.h Tue Oct 15 20:29:16 2002 @@ -74,7 +74,7 @@ ret = -EBUSY; \ break; \ } \ - schedule_timeout(max(HZ/100,1)); \ + schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \ if (signal_pending(current)) { \ ret = -EINTR; \ break; \ diff -Nru a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c --- a/drivers/char/drm/mga_dma.c Tue Oct 15 20:29:15 2002 +++ b/drivers/char/drm/mga_dma.c Tue Oct 15 20:29:15 2002 @@ -157,8 +157,17 @@ { drm_mga_primary_buffer_t *primary = &dev_priv->prim; u32 head, tail; - DMA_LOCALS; + u32 status = 0; + int i; + DMA_LOCALS; DRM_DEBUG( "\n" ); + + /* We need to wait so that we can do an safe flush */ + 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 ); + } if ( primary->tail == primary->last_flush ) { DRM_DEBUG( " bailing out...\n" ); diff -Nru a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c --- a/drivers/char/n_hdlc.c Tue Oct 15 20:29:15 2002 +++ b/drivers/char/n_hdlc.c Tue Oct 15 20:29:15 2002 @@ -9,7 +9,7 @@ * Al Longyear , Paul Mackerras * * Original release 01/11/99 - * $Id: n_hdlc.c,v 4.1 2002/04/10 19:30:58 paulkf Exp $ + * $Id: n_hdlc.c,v 4.2 2002/10/10 14:52:41 paulkf Exp $ * * This code is released under the GNU General Public License (GPL) * @@ -78,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "$Revision: 4.1 $" +#define HDLC_VERSION "$Revision: 4.2 $" #include #include @@ -264,7 +264,8 @@ } else break; } - + if (n_hdlc->tbuf) + kfree(n_hdlc->tbuf); kfree(n_hdlc); } /* end of n_hdlc_release() */ @@ -381,16 +382,15 @@ printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); check_again: - save_flags(flags); - cli (); + spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->tbusy) { n_hdlc->woke_up = 1; - restore_flags(flags); + spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); return; } n_hdlc->tbusy = 1; n_hdlc->woke_up = 0; - restore_flags(flags); + spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); /* get current transmit buffer or get new transmit */ /* buffer from list of pending transmit buffers */ @@ -445,10 +445,9 @@ tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); /* Clear the re-entry flag */ - save_flags(flags); - cli (); + spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); n_hdlc->tbusy = 0; - restore_flags(flags); + spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->woke_up) goto check_again; diff -Nru a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c --- a/drivers/char/n_r3964.c Tue Oct 15 20:29:22 2002 +++ b/drivers/char/n_r3964.c Tue Oct 15 20:29:22 2002 @@ -1126,7 +1126,7 @@ tty->disc_data = pInfo; - INIT_LIST_HEAD(&pInfo->tmr.list); + init_timer(&pInfo->tmr); pInfo->tmr.data = (unsigned long)pInfo; pInfo->tmr.function = on_timeout; diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c --- a/drivers/char/pcmcia/synclink_cs.c Tue Oct 15 20:29:16 2002 +++ b/drivers/char/pcmcia/synclink_cs.c Tue Oct 15 20:29:16 2002 @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.2 2002/04/22 14:36:43 paulkf Exp $ + * $Id: synclink_cs.c,v 4.4 2002/10/10 14:53:37 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -498,7 +498,7 @@ MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.2 $"; +static char *driver_version = "$Revision: 4.4 $"; static struct tty_driver serial_driver, callout_driver; static int serial_refcount; @@ -2741,7 +2741,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } } else { @@ -2751,7 +2751,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } } @@ -2849,12 +2849,12 @@ printk("%s(%d):block_til_ready before block on %s count=%d\n", __FILE__,__LINE__, tty->driver.name, info->count ); - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { extra_count = 1; info->count--; } - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); info->blocked_open++; while (1) { @@ -3319,7 +3319,6 @@ static void __exit synclink_cs_exit(void) { - unsigned long flags; int rc; printk("Unloading %s: version %s\n", driver_name, driver_version); @@ -3327,15 +3326,12 @@ while(mgslpc_device_list) mgslpc_remove_device(mgslpc_device_list); - save_flags(flags); - cli(); if ((rc = tty_unregister_driver(&serial_driver))) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); if ((rc = tty_unregister_driver(&callout_driver))) printk("%s(%d) failed to unregister callout driver err=%d\n", __FILE__,__LINE__,rc); - restore_flags(flags); unregister_pccard_driver(&dev_info); while (dev_list != NULL) { diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c --- a/drivers/char/rtc.c Tue Oct 15 20:29:16 2002 +++ b/drivers/char/rtc.c Tue Oct 15 20:29:16 2002 @@ -86,7 +86,9 @@ static int rtc_irq = PCI_IRQ_NONE; #endif +#if RTC_IRQ static int rtc_has_irq = 1; +#endif /* * We sponge a minor off of the misc major. No need slurping @@ -99,7 +101,9 @@ static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); +#if RTC_IRQ static struct timer_list rtc_irq_timer; +#endif static ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos); diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c Tue Oct 15 20:29:16 2002 +++ b/drivers/char/synclink.c Tue Oct 15 20:29:16 2002 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.2 2002/04/10 20:45:13 paulkf Exp $ + * $Id: synclink.c,v 4.4 2002/10/10 14:53:36 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -917,7 +917,7 @@ MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.2 $"; +static char *driver_version = "$Revision: 4.4 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -3387,7 +3387,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } } else { @@ -3397,7 +3397,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } } @@ -3512,12 +3512,12 @@ printk("%s(%d):block_til_ready before block on %s count=%d\n", __FILE__,__LINE__, tty->driver.name, info->count ); - save_flags(flags); cli(); + spin_lock_irqsave(&info->irq_spinlock, flags); if (!tty_hung_up_p(filp)) { extra_count = 1; info->count--; } - restore_flags(flags); + spin_unlock_irqrestore(&info->irq_spinlock, flags); info->blocked_open++; while (1) { @@ -4728,21 +4728,18 @@ static void __exit synclink_exit(void) { - unsigned long flags; int rc; struct mgsl_struct *info; struct mgsl_struct *tmp; printk("Unloading %s: %s\n", driver_name, driver_version); - save_flags(flags); - cli(); + if ((rc = tty_unregister_driver(&serial_driver))) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); if ((rc = tty_unregister_driver(&callout_driver))) printk("%s(%d) failed to unregister callout driver err=%d\n", __FILE__,__LINE__,rc); - restore_flags(flags); info = mgsl_device_list; while(info) { @@ -7486,7 +7483,7 @@ EndTime = jiffies + jiffies_from_ms(100); for(;;) { - if ( jiffies > EndTime ) { + if (time_after(jiffies, EndTime)) { rc = FALSE; break; } @@ -7542,7 +7539,7 @@ EndTime = jiffies + jiffies_from_ms(100); for(;;) { - if ( jiffies > EndTime ) { + if (time_after(jiffies, EndTime)) { rc = FALSE; break; } @@ -7590,7 +7587,7 @@ spin_unlock_irqrestore(&info->irq_spinlock,flags); while ( !(status & (BIT6+BIT5+BIT4+BIT2+BIT1)) ) { - if ( jiffies > EndTime ) { + if (time_after(jiffies, EndTime)) { rc = FALSE; break; } @@ -7617,8 +7614,7 @@ /* Wait for 16C32 to write receive status to buffer entry. */ status=info->rx_buffer_list[0].status; while ( status == 0 ) { - if ( jiffies > EndTime ) { - printk(KERN_ERR"mark 4\n"); + if (time_after(jiffies, EndTime)) { rc = FALSE; break; } diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c --- a/drivers/char/synclinkmp.c Tue Oct 15 20:29:12 2002 +++ b/drivers/char/synclinkmp.c Tue Oct 15 20:29:12 2002 @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 4.4 2002/04/22 16:05:41 paulkf Exp $ + * $Id: synclinkmp.c,v 4.6 2002/10/10 14:50:47 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -503,7 +503,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.4 $"; +static char *driver_version = "$Revision: 4.6 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -1204,7 +1204,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } } else { @@ -1215,7 +1215,7 @@ schedule_timeout(char_time); if (signal_pending(current)) break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) + if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } } @@ -2605,18 +2605,11 @@ info->pending_bh = 0; - init_timer(&info->tx_timer); - info->tx_timer.data = (unsigned long)info; - info->tx_timer.function = tx_timeout; - /* program hardware for current parameters */ reset_port(info); change_params(info); - init_timer(&info->status_timer); - info->status_timer.data = (unsigned long)info; - info->status_timer.function = status_timeout; info->status_timer.expires = jiffies + jiffies_from_ms(10); add_timer(&info->status_timer); @@ -3304,12 +3297,12 @@ printk("%s(%d):%s block_til_ready() before block, count=%d\n", __FILE__,__LINE__, tty->driver.name, info->count ); - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) { extra_count = 1; info->count--; } - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); info->blocked_open++; while (1) { @@ -3772,6 +3765,14 @@ info->bus_type = MGSL_BUS_TYPE_PCI; info->irq_flags = SA_SHIRQ; + init_timer(&info->tx_timer); + info->tx_timer.data = (unsigned long)info; + info->tx_timer.function = tx_timeout; + + init_timer(&info->status_timer); + info->status_timer.data = (unsigned long)info; + info->status_timer.function = status_timeout; + /* Store the PCI9050 misc control register value because a flaw * in the PCI9050 prevents LCR registers from being read if * BIOS assigns an LCR base address with bit 7 set. @@ -3959,15 +3960,13 @@ SLMP_INFO *tmp; printk("Unloading %s %s\n", driver_name, driver_version); - save_flags(flags); - cli(); + if ((rc = tty_unregister_driver(&serial_driver))) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); if ((rc = tty_unregister_driver(&callout_driver))) printk("%s(%d) failed to unregister callout driver err=%d\n", __FILE__,__LINE__,rc); - restore_flags(flags); info = synclinkmp_device_list; while(info) { diff -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/tipar.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,541 @@ +/* Hey EMACS -*- linux-c -*- + * + * tipar - low level driver for handling a parallel link cable designed + * for Texas Instruments graphing calculators (http://lpg.ticalc.org). + * A part of the TiLP project. + * + * Copyright (C) 2000-2002, Romain Lievin + * under the terms of the GNU General Public License. + * + * Various fixes & clean-up from the Linux Kernel Mailing List + * (Alan Cox, Richard B. Johnson, Christoph Hellwig). + */ + +/* This driver should, in theory, work with any parallel port that has an + * appropriate low-level driver; all I/O is done through the parport + * abstraction layer. + * + * If this driver is built into the kernel, you can configure it using the + * kernel command-line. For example: + * + * tipar=timeout,delay (set timeout and delay) + * + * If the driver is loaded as a module, similar functionality is available + * using module parameters. The equivalent of the above commands would be: + * + * # insmod tipar timeout=15 delay=10 + */ + +/* COMPATIBILITY WITH OLD KERNELS + * + * Usually, parallel cables were bound to ports at + * particular I/O addresses, as follows: + * + * tipar0 0x378 + * tipar1 0x278 + * tipar2 0x3bc + * + * + * This driver, by default, binds tipar devices according to parport and + * the minor number. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* DevFs support */ +#include /* Our code depend on parport */ + +/* + * TI definitions + */ +#include + +/* + * Version Information + */ +#define DRIVER_VERSION "1.17" +#define DRIVER_AUTHOR "Romain Lievin " +#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) +# define minor(x) MINOR(x) +# define need_resched() (current->need_resched) +#endif + +/* ----- global variables --------------------------------------------- */ + +struct tipar_struct { + struct pardevice *dev; /* Parport device entry */ +}; + +#define PP_NO 3 +static struct tipar_struct table[PP_NO]; + +static int delay = IO_DELAY; /* inter-bit delay in microseconds */ +static int timeout = TIMAXTIME; /* timeout in tenth of seconds */ + +static devfs_handle_t devfs_handle; +static unsigned int tp_count; /* tipar count */ +static unsigned long opened; /* opened devices */ + +/* --- macros for parport access -------------------------------------- */ + +#define r_dtr(x) (parport_read_data(table[(x)].dev->port)) +#define r_str(x) (parport_read_status(table[(x)].dev->port)) +#define w_ctr(x,y) (parport_write_control(table[(x)].dev->port, (y))) +#define w_dtr(x,y) (parport_write_data(table[(x)].dev->port, (y))) + +/* --- setting states on the D-bus with the right timing: ------------- */ + +static inline void +outbyte(int value, int minor) +{ + w_dtr(minor, value); +} + +static inline int +inbyte(int minor) +{ + return (r_str(minor)); +} + +static inline void +init_ti_parallel(int minor) +{ + outbyte(3, minor); +} + +/* ----- global defines ----------------------------------------------- */ + +#define START(x) { x=jiffies+HZ/(timeout/10); } +#define WAIT(x) { \ + if (time_before((x), jiffies)) return -1; \ + if (need_resched()) schedule(); } + +/* ----- D-bus bit-banging functions ---------------------------------- */ + +/* D-bus protocol (45kbit/s max): + 1 0 0 + _______ ______|______ __________|________ __________ +Red : ________ | ____ | ____ + _ ____________|________ ______|__________ _____ +White: ________ | ______ | _______ +*/ + +/* Try to transmit a byte on the specified port (-1 if error). */ +static int +put_ti_parallel(int minor, unsigned char data) +{ + int bit; + unsigned long max; + + for (bit = 0; bit < 8; bit++) { + if (data & 1) { + outbyte(2, minor); + START(max); + do { + WAIT(max); + } while (inbyte(minor) & 0x10); + + outbyte(3, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x10)); + } else { + outbyte(1, minor); + START(max); + do { + WAIT(max); + } while (inbyte(minor) & 0x20); + + outbyte(3, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x20)); + } + + data >>= 1; + udelay(delay); + + if (need_resched()) + schedule(); + } + + return 0; +} + +/* Receive a byte on the specified port or -1 if error. */ +static int +get_ti_parallel(int minor) +{ + int bit; + unsigned char v, data = 0; + unsigned long max; + + for (bit = 0; bit < 8; bit++) { + START(max); + do { + WAIT(max); + } while ((v = inbyte(minor) & 0x30) == 0x30); + + if (v == 0x10) { + data = (data >> 1) | 0x80; + outbyte(1, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x20)); + outbyte(3, minor); + } else { + data = data >> 1; + outbyte(2, minor); + START(max); + do { + WAIT(max); + } while (!(inbyte(minor) & 0x10)); + outbyte(3, minor); + } + + udelay(delay); + if (need_resched()) + schedule(); + } + + return (int) data; +} + +/* Try to detect a parallel link cable on the specified port */ +static int +probe_ti_parallel(int minor) +{ + int i; + int seq[] = { 0x00, 0x20, 0x10, 0x30 }; + + for (i = 3; i >= 0; i--) { + outbyte(3, minor); + outbyte(i, minor); + udelay(delay); + /*printk(KERN_DEBUG "Probing -> %i: 0x%02x 0x%02x\n", i, data & 0x30, seq[i]); */ + if ((inbyte(minor) & 0x30) != seq[i]) { + outbyte(3, minor); + return -1; + } + } + + outbyte(3, minor); + return 0; +} + +/* ----- kernel module functions--------------------------------------- */ + +static int +tipar_open(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR; + + if (minor > tp_count - 1) + return -ENXIO; + + if (test_and_set_bit(minor, &opened)) + return -EBUSY; + + parport_claim_or_block(table[minor].dev); + init_ti_parallel(minor); + parport_release(table[minor].dev); + + return 0; +} + +static int +tipar_close(struct inode *inode, struct file *file) +{ + unsigned int minor = minor(inode->i_rdev) - TIPAR_MINOR; + + if (minor > tp_count - 1) + return -ENXIO; + + clear_bit(minor, &opened); + + return 0; +} + +static ssize_t +tipar_write(struct file *file, const char *buf, size_t count, loff_t * ppos) +{ + unsigned int minor = + minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR; + ssize_t n; + + printk("_write\n"); + parport_claim_or_block(table[minor].dev); + + for (n = 0; n < count; n++) { + unsigned char b; + + if (get_user(b, buf + n)) { + n = -EFAULT; + goto out; + } + + if (put_ti_parallel(minor, b) == -1) { + init_ti_parallel(minor); + n = -ETIMEDOUT; + goto out; + } + } + out: + parport_release(table[minor].dev); + return n; +} + +static ssize_t +tipar_read(struct file *file, char *buf, size_t count, loff_t * ppos) +{ + int b = 0; + unsigned int minor = + minor(file->f_dentry->d_inode->i_rdev) - TIPAR_MINOR; + ssize_t retval = 0; + ssize_t n = 0; + + if (count == 0) + return 0; + + if (ppos != &file->f_pos) + return -ESPIPE; + + printk("_read\n"); + parport_claim_or_block(table[minor].dev); + + while (n < count) { + b = get_ti_parallel(minor); + if (b == -1) { + init_ti_parallel(minor); + retval = -ETIMEDOUT; + goto out; + } else { + if (put_user(b, ((unsigned char *) buf) + n)) { + retval = -EFAULT; + break; + } else + retval = ++n; + } + + /* Non-blocking mode : try again ! */ + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + /* Signal pending, try again ! */ + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + if (need_resched()) + schedule(); + } + + out: + parport_release(table[minor].dev); + return retval; +} + +static int +tipar_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + switch (cmd) { + case IOCTL_TIPAR_DELAY: + delay = (int)arg; //get_user(delay, &arg); + break; + case IOCTL_TIPAR_TIMEOUT: + timeout = (int)arg; //get_user(timeout, &arg); + break; + default: + retval = -ENOTTY; + break; + } + + return retval; +} + +/* ----- kernel module registering ------------------------------------ */ + +static struct file_operations tipar_fops = { + owner:THIS_MODULE, + llseek:no_llseek, + read:tipar_read, + write:tipar_write, + ioctl:tipar_ioctl, + open:tipar_open, + release:tipar_close, +}; + +/* --- initialisation code ------------------------------------- */ + +#ifndef MODULE +/* You must set these - there is no sane way to probe for this cable. + * You can use 'tipar=timeout,delay' to set these now. */ +static int __init +tipar_setup(char *str) +{ + int ints[2]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + if (ints[0] > 0) { + timeout = ints[1]; + if (ints[0] > 1) { + delay = ints[2]; + } + } + + return 1; +} +#endif + +/* + * Register our module into parport. + * Pass also 2 callbacks functions to parport: a pre-emptive function and an + * interrupt handler function (unused). + * Display a message such "tipar0: using parport0 (polling)". + */ +static int +tipar_register(int nr, struct parport *port) +{ + char name[8]; + + /* Register our module into parport */ + table[nr].dev = parport_register_device(port, "tipar", + NULL, NULL, NULL, 0, + (void *) &table[nr]); + + if (table[nr].dev == NULL) + return 1; + + /* Use devfs, tree: /dev/ticables/par/[0..2] */ + sprintf(name, "%d", nr); + printk + ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n", + TISER_MAJOR, (TIPAR_MINOR + nr), name); + devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR, + TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO, + &tipar_fops, NULL); + + /* Display informations */ + printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name, + (port->irq == + PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven"); + + if (probe_ti_parallel(nr) != -1) + printk("tipar%d: link cable found !\n", nr); + else + printk("tipar%d: link cable not found.\n", nr); + + return 0; +} + +static void +tipar_attach(struct parport *port) +{ + if (tp_count == PP_NO) { + printk("tipar: ignoring parallel port (max. %d)\n", PP_NO); + return; + } + + if (!tipar_register(tp_count, port)) + tp_count++; +} + +static void +tipar_detach(struct parport *port) +{ + /* Nothing to do */ +} + +static struct parport_driver tipar_driver = { + "tipar", + tipar_attach, + tipar_detach, + NULL +}; + +int __init +tipar_init_module(void) +{ + printk("tipar: parallel link cable driver, version %s\n", + DRIVER_VERSION); + + if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) { + printk("tipar: unable to get major %d\n", TIPAR_MAJOR); + return -EIO; + } + + /* Use devfs with tree: /dev/ticables/par/[0..2] */ + devfs_handle = devfs_mk_dir(NULL, "ticables/par", NULL); + + if (parport_register_driver(&tipar_driver)) { + printk("tipar: unable to register with parport\n"); + return -EIO; + } + + return 0; +} + +void __exit +tipar_cleanup_module(void) +{ + unsigned int i; + + /* Unregistering module */ + parport_unregister_driver(&tipar_driver); + + devfs_unregister(devfs_handle); + unregister_chrdev(TIPAR_MAJOR, "tipar"); + + for (i = 0; i < PP_NO; i++) { + if (table[i].dev == NULL) + continue; + parport_unregister_device(table[i].dev); + } + + printk("tipar: module unloaded !\n"); +} + +/* --------------------------------------------------------------------- */ + +__setup("tipar=", tipar_setup); +module_init(tipar_init_module); +module_exit(tipar_cleanup_module); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE(DRIVER_LICENSE); + +EXPORT_NO_SYMBOLS; + +MODULE_PARM(timeout, "i"); +MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)"); +MODULE_PARM(delay, "i"); +MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)"); diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Tue Oct 15 20:29:17 2002 +++ b/drivers/char/tty_io.c Tue Oct 15 20:29:17 2002 @@ -113,7 +113,7 @@ #define CHECK_TTY_COUNT 1 struct termios tty_std_termios; /* for the benefit of tty drivers */ -struct tty_driver *tty_drivers; /* linked list of tty drivers */ +LIST_HEAD(tty_drivers); /* linked list of tty drivers */ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ #ifdef CONFIG_UNIX98_PTYS @@ -338,7 +338,7 @@ minor = minor(device); major = major(device); - for (p = tty_drivers; p; p = p->next) { + list_for_each_entry(p, &tty_drivers, tty_drivers) { if (p->major != major) continue; if (minor < p->minor_start) @@ -2083,10 +2083,7 @@ if (!driver->put_char) driver->put_char = tty_default_put_char; - driver->prev = 0; - driver->next = tty_drivers; - if (tty_drivers) tty_drivers->prev = driver; - tty_drivers = driver; + list_add(&driver->tty_drivers, &tty_drivers); if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) { for(i = 0; i < driver->num; i++) @@ -2110,7 +2107,7 @@ if (*driver->refcount) return -EBUSY; - for (p = tty_drivers; p; p = p->next) { + list_for_each_entry(p, &tty_drivers, tty_drivers) { if (p == driver) found++; else if (p->major == driver->major) @@ -2127,13 +2124,7 @@ } else register_chrdev(driver->major, othername, &tty_fops); - if (driver->prev) - driver->prev->next = driver->next; - else - tty_drivers = driver->next; - - if (driver->next) - driver->next->prev = driver->prev; + list_del(&driver->tty_drivers); /* * Free the termios and termios_locked structures because diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Tue Oct 15 20:29:16 2002 +++ b/drivers/ide/ide-cd.c Tue Oct 15 20:29:16 2002 @@ -309,6 +309,8 @@ #include #include +#include /* For SCSI -> ATAPI command conversion */ + #include #include #include @@ -332,12 +334,12 @@ info->nsectors_buffered = 0; } -static int cdrom_log_sense(ide_drive_t *drive, struct packet_command *pc, +static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, struct request_sense *sense) { int log = 0; - if (sense == NULL || pc == NULL || pc->quiet) + if (!sense || !rq || (rq->flags & REQ_QUIET)) return 0; switch (sense->sense_key) { @@ -370,10 +372,9 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, - struct packet_command *failed_command, + struct request *failed_command, struct request_sense *sense) { - if (!cdrom_log_sense(drive, failed_command, sense)) return; @@ -382,7 +383,7 @@ * the first toc has not been recorded yet, it will fail with * 05/24/00 (which is a confusing error) */ - if (failed_command && failed_command->c[0] == GPCMD_READ_TOC_PMA_ATIP) + if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP) if (sense->sense_key == 0x05 && sense->asc == 0x24) return; @@ -453,20 +454,20 @@ while (hi > lo) { mid = (lo + hi) / 2; if (packet_command_texts[mid].packet_command == - failed_command->c[0]) { + failed_command->cmd[0]) { s = packet_command_texts[mid].text; break; } if (packet_command_texts[mid].packet_command > - failed_command->c[0]) + failed_command->cmd[0]) hi = mid; else lo = mid+1; } printk (" The failed \"%s\" packet command was: \n \"", s); - for (i=0; ic); i++) - printk ("%02x ", failed_command->c[i]); + for (i=0; icmd); i++) + printk ("%02x ", failed_command->cmd[i]); printk ("\"\n"); } @@ -512,30 +513,39 @@ #endif /* not VERBOSE_IDE_CD_ERRORS */ } +/* + * Initialize a ide-cd packet command request + */ +static void cdrom_prepare_request(struct request *rq) +{ + ide_init_drive_cmd(rq); + rq->flags = REQ_PC; +} + static void cdrom_queue_request_sense(ide_drive_t *drive, struct completion *wait, - struct request_sense *sense, - struct packet_command *failed_command) + void *sense, + struct request *failed_command) { struct cdrom_info *info = drive->driver_data; - struct packet_command *pc = &info->request_sense_pc; - struct request *rq; + struct request *rq = &info->request_sense_request; if (sense == NULL) sense = &info->sense_data; - memset(pc, 0, sizeof(struct packet_command)); - pc->c[0] = GPCMD_REQUEST_SENSE; - pc->c[4] = pc->buflen = 18; - pc->buffer = (char *) sense; - pc->sense = (struct request_sense *) failed_command; - /* stuff the sense request in front of our current request */ - rq = &info->request_sense_request; - ide_init_drive_cmd(rq); + cdrom_prepare_request(rq); + + rq->data = sense; + rq->cmd[0] = GPCMD_REQUEST_SENSE; + rq->cmd[4] = rq->data_len = 18; + rq->flags = REQ_SENSE; - rq->buffer = (char *) pc; rq->waiting = wait; + + /* NOTE! Save the failed command in "rq->buffer" */ + rq->buffer = (void *) failed_command; + (void) ide_do_drive_cmd(drive, rq, ide_preempt); } @@ -630,17 +640,26 @@ struct request *rq = HWGROUP(drive)->rq; if ((rq->flags & REQ_SENSE) && uptodate) { - struct packet_command *pc = (struct packet_command *) rq->buffer; - cdrom_analyze_sense_data(drive, - (struct packet_command *) pc->sense, - (struct request_sense *) (pc->buffer - pc->c[4])); + /* For REQ_SENSE, "rq->buffer" points to the original failed request */ + struct request *failed = (struct request *) rq->buffer; + struct cdrom_info *info = drive->driver_data; + void * sense = &info->sense_data; + + if (failed && failed->sense) + sense = failed->sense; + + cdrom_analyze_sense_data(drive, failed, sense); } + if (blk_fs_request(rq) && !rq->current_nr_sectors) uptodate = 1; ide_end_request(drive, uptodate, rq->hard_cur_sectors); } +/* Handle differences between SCSI and ATAPI packet commands */ +static int pre_transform_command(struct request *); +static void post_transform_command(struct request *); /* Returns 0 if the request should be continued. Returns 1 if the request was ended. */ @@ -649,7 +668,6 @@ { struct request *rq = HWGROUP(drive)->rq; int stat, err, sense_key; - struct packet_command *pc; /* Check for errors. */ *stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG); @@ -672,16 +690,18 @@ from the drive (probably while trying to recover from a former error). Just give up. */ - pc = (struct packet_command *) rq->buffer; - pc->stat = 1; - cdrom_end_request(drive, 1); + rq->flags |= REQ_FAILED; + cdrom_end_request(drive, 0); *startstop = DRIVER(drive)->error(drive, "request sense failure", stat); return 1; - } else if (rq->flags & REQ_PC) { + } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) { /* All other functions, except for READ. */ struct completion *wait = NULL; - pc = (struct packet_command *) rq->buffer; + + /* Fix up any SCSI command differences.. */ + if (rq->flags & REQ_BLOCK_PC) + post_transform_command(rq); /* Check for tray open. */ if (sense_key == NOT_READY) { @@ -691,7 +711,7 @@ cdrom_saw_media_change (drive); /*printk("%s: media changed\n",drive->name);*/ return 0; - } else if (!pc->quiet) { + } else if (!(rq->flags & REQ_QUIET)) { /* Otherwise, print an error. */ ide_dump_status(drive, "packet command error", stat); } @@ -710,11 +730,11 @@ rq->waiting = NULL; } - pc->stat = 1; - cdrom_end_request(drive, 1); + rq->flags |= REQ_FAILED; + cdrom_end_request(drive, 0); if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, wait, pc->sense, pc); + cdrom_queue_request_sense(drive, wait, rq->sense, rq); } else if (blk_fs_request(rq)) { /* Handle errors from READ and WRITE requests. */ @@ -770,7 +790,6 @@ static int cdrom_timer_expiry(ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *) rq->buffer; unsigned long wait = 0; /* @@ -779,7 +798,7 @@ * this, but not all commands/drives support that. Let * ide_timer_expiry keep polling us for these. */ - switch (pc->c[0]) { + switch (rq->cmd[0]) { case GPCMD_BLANK: case GPCMD_FORMAT_UNIT: case GPCMD_RESERVE_RZONE_TRACK: @@ -854,12 +873,12 @@ * struct packet_command *pc; now packet_command_t *pc; */ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, - struct packet_command *pc, + struct request *rq, ide_handler_t *handler) { - unsigned char *cmd_buf = pc->c; - int cmd_len = sizeof(pc->c); - unsigned int timeout = pc->timeout; + unsigned char *cmd_buf = rq->cmd; + int cmd_len = sizeof(rq->cmd); + unsigned int timeout = rq->timeout; struct cdrom_info *info = drive->driver_data; ide_startstop_t startstop; @@ -1029,6 +1048,7 @@ if (rq->current_nr_sectors > 0) { printk ("%s: cdrom_read_intr: data underrun (%d blocks)\n", drive->name, rq->current_nr_sectors); + rq->flags |= REQ_FAILED; cdrom_end_request(drive, 0); } else cdrom_end_request(drive, 1); @@ -1179,7 +1199,6 @@ */ static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive) { - struct packet_command pc; struct request *rq = HWGROUP(drive)->rq; int nsect, sector, nframes, frame, nskip; @@ -1222,11 +1241,10 @@ (65534 / CD_FRAMESIZE) : 65535); /* Set up the command */ - memcpy(pc.c, rq->cmd, sizeof(pc.c)); - pc.timeout = WAIT_CMD; + rq->timeout = WAIT_CMD; /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr); + return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr); } @@ -1262,7 +1280,6 @@ static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive) { - struct packet_command pc; struct request *rq = HWGROUP(drive)->rq; int sector, frame, nskip; @@ -1273,11 +1290,11 @@ frame = sector / SECTORS_PER_FRAME; memset(rq->cmd, 0, sizeof(rq->cmd)); - pc.c[0] = GPCMD_SEEK; - put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]); + rq->cmd[0] = GPCMD_SEEK; + put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]); - pc.timeout = WAIT_CMD; - return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr); + rq->timeout = WAIT_CMD; + return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr); } static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block) @@ -1296,6 +1313,7 @@ { if (rq->buffer != bio_data(rq->bio)) { sector_t n = (rq->buffer - (char *) bio_data(rq->bio)) / SECTOR_SIZE; + rq->buffer = bio_data(rq->bio); rq->nr_sectors += n; rq->sector -= n; @@ -1352,7 +1370,6 @@ { int ireason, len, stat, thislen; struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *)rq->buffer; ide_startstop_t startstop; u8 lowcyl = 0, highcyl = 0; @@ -1372,16 +1389,16 @@ if ((stat & DRQ_STAT) == 0) { /* Some of the trailing request sense fields are optional, and some drives don't send them. Sigh. */ - if (pc->c[0] == GPCMD_REQUEST_SENSE && - pc->buflen > 0 && - pc->buflen <= 5) { - while (pc->buflen > 0) { - *pc->buffer++ = 0; - --pc->buflen; + if (rq->cmd[0] == GPCMD_REQUEST_SENSE && + rq->data_len > 0 && + rq->data_len <= 5) { + while (rq->data_len > 0) { + *(unsigned char *)rq->data++ = 0; + --rq->data_len; } } - if (pc->buflen == 0) + if (rq->data_len == 0) cdrom_end_request(drive, 1); else { /* Comment this out, because this always happens @@ -1391,20 +1408,22 @@ printk ("%s: cdrom_pc_intr: data underrun %d\n", drive->name, pc->buflen); */ - pc->stat = 1; - cdrom_end_request(drive, 1); + rq->flags |= REQ_FAILED; + cdrom_end_request(drive, 0); } return ide_stopped; } /* Figure out how much data to transfer. */ - thislen = pc->buflen; + thislen = rq->data_len; if (thislen > len) thislen = len; /* The drive wants to be written to. */ if ((ireason & 3) == 0) { + if (!rq->data) + goto confused; /* Transfer the data. */ - HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen); + HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen); /* If we haven't moved enough data to satisfy the drive, add some padding. */ @@ -1415,15 +1434,16 @@ } /* Keep count of how much data we've moved. */ - pc->buffer += thislen; - pc->buflen -= thislen; + rq->data += thislen; + rq->data_len -= thislen; } /* Same drill for reading. */ else if ((ireason & 3) == 2) { - + if (!rq->data) + goto confused; /* Transfer the data. */ - HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen); + HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen); /* If we haven't moved enough data to satisfy the drive, add some padding. */ @@ -1434,13 +1454,14 @@ } /* Keep count of how much data we've moved. */ - pc->buffer += thislen; - pc->buflen -= thislen; + rq->data += thislen; + rq->data_len -= thislen; } else { +confused: printk ("%s: cdrom_pc_intr: The drive " "appears confused (ireason = 0x%2x)\n", drive->name, ireason); - pc->stat = 1; + rq->flags |= REQ_FAILED; } if (HWGROUP(drive)->handler != NULL) @@ -1455,13 +1476,12 @@ static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive) { struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *)rq->buffer; - if (!pc->timeout) - pc->timeout = WAIT_CMD; + if (!rq->timeout) + rq->timeout = WAIT_CMD; /* Send the command to the drive and return. */ - return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr); + return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr); } @@ -1469,13 +1489,12 @@ { int len; struct request *rq = HWGROUP(drive)->rq; - struct packet_command *pc = (struct packet_command *)rq->buffer; struct cdrom_info *info = drive->driver_data; info->dma = 0; info->cmd = 0; - pc->stat = 0; - len = pc->buflen; + rq->flags &= ~REQ_FAILED; + len = rq->data_len; /* Start sending the command to the drive. */ return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation); @@ -1496,28 +1515,31 @@ } static -int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc) +int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) { struct request_sense sense; - struct request req; int retries = 10; + unsigned int flags = rq->flags; - if (pc->sense == NULL) - pc->sense = &sense; + if (rq->sense == NULL) + rq->sense = &sense; /* Start of retry loop. */ do { - ide_init_drive_cmd (&req); - req.flags = REQ_PC; - req.buffer = (char *)pc; - ide_do_drive_cmd(drive, &req, ide_wait); + int error; + unsigned long time = jiffies; + rq->flags = flags; + + error = ide_do_drive_cmd(drive, rq, ide_wait); + time = jiffies - time; + /* FIXME: we should probably abort/retry or something * in case of failure */ - if (pc->stat != 0) { + if (rq->flags & REQ_FAILED) { /* The request failed. Retry if it was due to a unit attention status (usually means media was changed). */ - struct request_sense *reqbuf = pc->sense; + struct request_sense *reqbuf = rq->sense; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change(drive); @@ -1535,10 +1557,10 @@ } /* End of retry loop. */ - } while (pc->stat != 0 && retries >= 0); + } while ((rq->flags & REQ_FAILED) && retries >= 0); /* Return an error if the command failed. */ - return pc->stat ? -EIO : 0; + return (rq->flags & REQ_FAILED) ? -EIO : 0; } /* @@ -1681,20 +1703,18 @@ static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive) { - struct packet_command pc; /* packet_command_t pc; */ struct request *rq = HWGROUP(drive)->rq; unsigned nframes, frame; nframes = rq->nr_sectors >> 2; frame = rq->sector >> 2; - memcpy(pc.c, rq->cmd, sizeof(pc.c)); #if 0 /* the immediate bit */ - pc.c[1] = 1 << 3; + rq->cmd[1] = 1 << 3; #endif - pc.timeout = 2 * WAIT_CMD; + rq->timeout = 2 * WAIT_CMD; - return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr); + return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr); } static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq) @@ -1728,20 +1748,54 @@ return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont); } +/* + * Most of the SCSI commands are supported directly by ATAPI devices. + * This transform handles the few exceptions. + */ +static int pre_transform_command(struct request *req) +{ + u8 *c = req->cmd; + /* Transform 6-byte read/write commands to the 10-byte version. */ + if (c[0] == READ_6 || c[0] == WRITE_6) { + c[8] = c[4]; + c[5] = c[3]; + c[4] = c[2]; + c[3] = c[1] & 0x1f; + c[2] = 0; + c[1] &= 0xe0; + c[0] += (READ_10 - READ_6); + return 0; + } + + /* These also need fixup, not done yet */ + if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) + return -EINVAL; + + return 0; +} + +static void post_transform_command(struct request *req) +{ +} + static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) { - struct packet_command pc; ide_startstop_t startstop; + struct cdrom_info *info; - memset(&pc, 0, sizeof(pc)); - memcpy(pc.c, rq->cmd, sizeof(pc.c)); - pc.quiet = 1; - pc.timeout = 60 * HZ; - rq->buffer = (char *) &pc; - - startstop = cdrom_do_packet_command(drive); - if (pc.stat) - rq->errors++; + if (pre_transform_command(rq) < 0) { + cdrom_end_request(drive, 0); + return ide_stopped; + } + + rq->flags |= REQ_QUIET; + + info = drive->driver_data; + info->dma = 0; + info->cmd = 0; + + /* Start sending the command to the drive. */ + startstop = cdrom_start_packet_command(drive, rq->data_len, cdrom_do_pc_continuation); return startstop; } @@ -1757,11 +1811,11 @@ if (blk_fs_request(rq)) { if (CDROM_CONFIG_FLAGS(drive)->seeking) { - unsigned long elpased = jiffies - info->start_seek; + unsigned long elapsed = jiffies - info->start_seek; int stat = HWIF(drive)->INB(IDE_STATUS_REG); if ((stat & SEEK_STAT) != SEEK_STAT) { - if (elpased < IDECD_SEEK_TIMEOUT) { + if (elapsed < IDECD_SEEK_TIMEOUT) { ide_stall_queue(drive, IDECD_SEEK_TIMER); return ide_stopped; } @@ -1781,14 +1835,14 @@ return action; } else if (rq->flags & (REQ_PC | REQ_SENSE)) { return cdrom_do_packet_command(drive); + } else if (rq->flags & REQ_BLOCK_PC) { + return cdrom_do_block_pc(drive, rq); } else if (rq->flags & REQ_SPECIAL) { /* * right now this can only be a reset... */ cdrom_end_request(drive, 1); return ide_stopped; - } else if (rq->flags & REQ_BLOCK_PC) { - return cdrom_do_block_pc(drive, rq); } blk_dump_rq_flags(rq, "ide-cd bad flags"); @@ -1853,23 +1907,23 @@ static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense) { - struct packet_command pc; + struct request req; struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; - memset(&pc, 0, sizeof(pc)); - pc.sense = sense; + cdrom_prepare_request(&req); - pc.c[0] = GPCMD_TEST_UNIT_READY; + req.sense = sense; + req.cmd[0] = GPCMD_TEST_UNIT_READY; #if ! STANDARD_ATAPI /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to switch CDs instead of supporting the LOAD_UNLOAD opcode */ - pc.c[7] = cdi->sanyo_slot % 3; + req.cmd[7] = cdi->sanyo_slot % 3; #endif /* not STANDARD_ATAPI */ - return cdrom_queue_packet_command(drive, &pc); + return cdrom_queue_packet_command(drive, &req); } @@ -1878,7 +1932,7 @@ cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense) { struct request_sense my_sense; - struct packet_command pc; + struct request req; int stat; if (sense == NULL) @@ -1888,11 +1942,11 @@ if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) { stat = 0; } else { - memset(&pc, 0, sizeof(pc)); - pc.sense = sense; - pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; - pc.c[4] = lockflag ? 1 : 0; - stat = cdrom_queue_packet_command(drive, &pc); + cdrom_prepare_request(&req); + req.sense = sense; + req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL; + req.cmd[4] = lockflag ? 1 : 0; + stat = cdrom_queue_packet_command(drive, &req); } /* If we got an illegal field error, the drive @@ -1922,7 +1976,7 @@ static int cdrom_eject(ide_drive_t *drive, int ejectflag, struct request_sense *sense) { - struct packet_command pc; + struct request req; if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag) return -EDRIVE_CANT_DO_THIS; @@ -1931,12 +1985,12 @@ if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag) return 0; - memset(&pc, 0, sizeof (pc)); - pc.sense = sense; + cdrom_prepare_request(&req); - pc.c[0] = GPCMD_START_STOP_UNIT; - pc.c[4] = 0x02 + (ejectflag != 0); - return cdrom_queue_packet_command(drive, &pc); + req.sense = sense; + req.cmd[0] = GPCMD_START_STOP_UNIT; + req.cmd[4] = 0x02 + (ejectflag != 0); + return cdrom_queue_packet_command(drive, &req); } static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity, @@ -1948,16 +2002,16 @@ } capbuf; int stat; - struct packet_command pc; + struct request req; - memset(&pc, 0, sizeof(pc)); - pc.sense = sense; + cdrom_prepare_request(&req); - pc.c[0] = GPCMD_READ_CDVD_CAPACITY; - pc.buffer = (char *)&capbuf; - pc.buflen = sizeof(capbuf); + req.sense = sense; + req.cmd[0] = GPCMD_READ_CDVD_CAPACITY; + req.data = (char *)&capbuf; + req.data_len = sizeof(capbuf); - stat = cdrom_queue_packet_command(drive, &pc); + stat = cdrom_queue_packet_command(drive, &req); if (stat == 0) *capacity = 1 + be32_to_cpu(capbuf.lba); @@ -1968,24 +2022,24 @@ int format, char *buf, int buflen, struct request_sense *sense) { - struct packet_command pc; + struct request req; - memset(&pc, 0, sizeof(pc)); - pc.sense = sense; + cdrom_prepare_request(&req); - pc.buffer = buf; - pc.buflen = buflen; - pc.quiet = 1; - pc.c[0] = GPCMD_READ_TOC_PMA_ATIP; - pc.c[6] = trackno; - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - pc.c[9] = (format << 6); + req.sense = sense; + req.data = buf; + req.data_len = buflen; + req.flags |= REQ_QUIET; + req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + req.cmd[6] = trackno; + req.cmd[7] = (buflen >> 8); + req.cmd[8] = (buflen & 0xff); + req.cmd[9] = (format << 6); if (msf_flag) - pc.c[1] = 2; + req.cmd[1] = 2; - return cdrom_queue_packet_command(drive, &pc); + return cdrom_queue_packet_command(drive, &req); } @@ -2144,20 +2198,20 @@ static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf, int buflen, struct request_sense *sense) { - struct packet_command pc; + struct request req; - memset(&pc, 0, sizeof(pc)); - pc.sense = sense; + cdrom_prepare_request(&req); - pc.buffer = buf; - pc.buflen = buflen; - pc.c[0] = GPCMD_READ_SUBCHANNEL; - pc.c[1] = 2; /* MSF addressing */ - pc.c[2] = 0x40; /* request subQ data */ - pc.c[3] = format; - pc.c[7] = (buflen >> 8); - pc.c[8] = (buflen & 0xff); - return cdrom_queue_packet_command(drive, &pc); + req.sense = sense; + req.data = buf; + req.data_len = buflen; + req.cmd[0] = GPCMD_READ_SUBCHANNEL; + req.cmd[1] = 2; /* MSF addressing */ + req.cmd[2] = 0x40; /* request subQ data */ + req.cmd[3] = format; + req.cmd[7] = (buflen >> 8); + req.cmd[8] = (buflen & 0xff); + return cdrom_queue_packet_command(drive, &req); } /* ATAPI cdrom drives are free to select the speed you request or any slower @@ -2165,45 +2219,45 @@ static int cdrom_select_speed(ide_drive_t *drive, int speed, struct request_sense *sense) { - struct packet_command pc; - memset(&pc, 0, sizeof(pc)); - pc.sense = sense; + struct request req; + cdrom_prepare_request(&req); + req.sense = sense; if (speed == 0) speed = 0xffff; /* set to max */ else speed *= 177; /* Nx to kbytes/s */ - pc.c[0] = GPCMD_SET_SPEED; + req.cmd[0] = GPCMD_SET_SPEED; /* Read Drive speed in kbytes/second MSB */ - pc.c[2] = (speed >> 8) & 0xff; + req.cmd[2] = (speed >> 8) & 0xff; /* Read Drive speed in kbytes/second LSB */ - pc.c[3] = speed & 0xff; + req.cmd[3] = speed & 0xff; if (CDROM_CONFIG_FLAGS(drive)->cd_r || CDROM_CONFIG_FLAGS(drive)->cd_rw || CDROM_CONFIG_FLAGS(drive)->dvd_r) { /* Write Drive speed in kbytes/second MSB */ - pc.c[4] = (speed >> 8) & 0xff; + req.cmd[4] = (speed >> 8) & 0xff; /* Write Drive speed in kbytes/second LSB */ - pc.c[5] = speed & 0xff; + req.cmd[5] = speed & 0xff; } - return cdrom_queue_packet_command(drive, &pc); + return cdrom_queue_packet_command(drive, &req); } static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end) { struct request_sense sense; - struct packet_command pc; + struct request req; - memset(&pc, 0, sizeof (pc)); - pc.sense = &sense; + cdrom_prepare_request(&req); - pc.c[0] = GPCMD_PLAY_AUDIO_MSF; - lba_to_msf(lba_start, &pc.c[3], &pc.c[4], &pc.c[5]); - lba_to_msf(lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]); + req.sense = &sense; + req.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + lba_to_msf(lba_start, &req.cmd[3], &req.cmd[4], &req.cmd[5]); + lba_to_msf(lba_end-1, &req.cmd[6], &req.cmd[7], &req.cmd[8]); - return cdrom_queue_packet_command(drive, &pc); + return cdrom_queue_packet_command(drive, &req); } static int cdrom_get_toc_entry(ide_drive_t *drive, int track, @@ -2237,7 +2291,7 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) { - struct packet_command pc; + struct request req; ide_drive_t *drive = (ide_drive_t*) cdi->handle; if (cgc->timeout <= 0) @@ -2246,18 +2300,21 @@ /* here we queue the commands from the uniform CD-ROM layer. the packet must be complete, as we do not touch it at all. */ - memset(&pc, 0, sizeof(pc)); - memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE); + cdrom_prepare_request(&req); + memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE); if (cgc->sense) memset(cgc->sense, 0, sizeof(struct request_sense)); - pc.buffer = cgc->buffer; - pc.buflen = cgc->buflen; - pc.quiet = cgc->quiet; - pc.timeout = cgc->timeout; - pc.sense = cgc->sense; - cgc->stat = cdrom_queue_packet_command(drive, &pc); + req.data = cgc->buffer; + req.data_len = cgc->buflen; + req.timeout = cgc->timeout; + + if (cgc->quiet) + req.flags |= REQ_QUIET; + + req.sense = cgc->sense; + cgc->stat = cdrom_queue_packet_command(drive, &req); if (!cgc->stat) - cgc->buflen -= pc.buflen; + cgc->buflen -= req.data_len; return cgc->stat; } @@ -2393,7 +2450,7 @@ struct request req; int ret; - ide_init_drive_cmd (&req); + cdrom_prepare_request(&req); req.flags = REQ_SPECIAL; ret = ide_do_drive_cmd(drive, &req, ide_wait); @@ -2969,6 +3026,14 @@ struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + int error; + + /* Try the generic SCSI command ioctl's first.. */ + error = scsi_cmd_ioctl(inode->i_bdev, cmd, arg); + if (error != -ENOTTY) + return error; + + /* Then the generic cdrom ioctl's.. */ return cdrom_ioctl(inode, file, cmd, arg); } @@ -3128,8 +3193,10 @@ memset(info, 0, sizeof (struct cdrom_info)); drive->driver_data = info; DRIVER(drive)->busy++; + g->minors = 1; g->minor_shift = 0; g->de = drive->de; + g->driverfs_dev = &drive->gendev; g->flags = GENHD_FL_CD; if (ide_cdrom_setup(drive)) { struct cdrom_device_info *devinfo = &info->devinfo; diff -Nru a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h --- a/drivers/ide/ide-cd.h Tue Oct 15 20:29:23 2002 +++ b/drivers/ide/ide-cd.h Tue Oct 15 20:29:23 2002 @@ -105,13 +105,6 @@ #define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags)) struct packet_command { - char *buffer; - int buflen; - int stat; - int quiet; - int timeout; - struct request_sense *sense; - unsigned char c[12]; }; /* Structure of a MSF cdrom address. */ @@ -437,7 +430,7 @@ byte curlba[3]; byte nslots; - __u8 short slot_tablelen; + __u16 slot_tablelen; }; diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Tue Oct 15 20:29:16 2002 +++ b/drivers/ide/ide-disk.c Tue Oct 15 20:29:16 2002 @@ -1871,8 +1871,10 @@ goto failed; } DRIVER(drive)->busy--; + g->minors = 1 << PARTN_BITS; g->minor_shift = PARTN_BITS; g->de = drive->de; + g->driverfs_dev = &drive->gendev; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; g->flags |= GENHD_FL_DEVFS; set_capacity(g, current_capacity(drive)); @@ -1891,78 +1893,6 @@ { ide_register_driver(&idedisk_driver); return 0; -} - -ide_startstop_t panic_box(ide_drive_t *drive) -{ -#if 0 - panic("%s: Attempted to corrupt something: ide operation " -#else - printk(KERN_ERR "%s: Attempted to corrupt something: ide operation " -#endif - "was pending accross suspend/resume.\n", drive->name); - return ide_stopped; -} - -int ide_disks_busy(void) -{ - int i; - for (i=0; ihandler) && (hwgroup->handler != panic_box)) - return 1; - } - return 0; -} - -void ide_disk_suspend(void) -{ - int i; - while (ide_disks_busy()) { - printk("*"); - schedule(); - } - for (i=0; ihandler_save = hwgroup->handler; - hwgroup->handler = panic_box; - } - driver_blocked = 1; - if (ide_disks_busy()) - panic("How did you get that request through?!"); -} - -/* unsuspend and resume should be equal in the ideal world */ - -void ide_disk_unsuspend(void) -{ - int i; - for (i=0; ihandler = NULL; /* hwgroup->handler_save; */ - hwgroup->handler_save = NULL; - } - driver_blocked = 0; -} - -void ide_disk_resume(void) -{ - int i; - for (i=0; ihandler != panic_box) - panic("Handler was not set to panic?"); - hwgroup->handler_save = NULL; - hwgroup->handler = NULL; - } - driver_blocked = 0; } module_init(idedisk_init); diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c --- a/drivers/ide/ide-floppy.c Tue Oct 15 20:29:17 2002 +++ b/drivers/ide/ide-floppy.c Tue Oct 15 20:29:17 2002 @@ -2108,7 +2108,9 @@ DRIVER(drive)->busy++; idefloppy_setup (drive, floppy); DRIVER(drive)->busy--; + g->minors = 1 << PARTN_BITS; g->minor_shift = PARTN_BITS; + g->driverfs_dev = &drive->gendev; g->de = drive->de; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; g->flags |= GENHD_FL_DEVFS; diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c --- a/drivers/ide/ide-probe.c Tue Oct 15 20:29:17 2002 +++ b/drivers/ide/ide-probe.c Tue Oct 15 20:29:17 2002 @@ -986,7 +986,7 @@ units = MAX_DRIVES; for (unit = 0; unit < MAX_DRIVES; unit++) { - disks[unit] = alloc_disk(); + disks[unit] = alloc_disk(1 << PARTN_BITS); if (!disks[unit]) goto err_kmalloc_gd; } @@ -996,7 +996,6 @@ disk->major = hwif->major; disk->first_minor = unit << PARTN_BITS; sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit); - disk->minor_shift = PARTN_BITS; disk->fops = ide_fops; hwif->drives[unit].disk = disk; } diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Tue Oct 15 20:29:15 2002 +++ b/drivers/ide/ide.c Tue Oct 15 20:29:15 2002 @@ -2639,7 +2639,7 @@ case CDROMEJECT: case CDROMCLOSETRAY: - return block_ioctl(inode->i_bdev, cmd, arg); + return scsi_cmd_ioctl(inode->i_bdev, cmd, arg); case HDIO_GET_BUSSTATE: if (!capable(CAP_SYS_ADMIN)) diff -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c --- a/drivers/ide/legacy/hd.c Tue Oct 15 20:29:11 2002 +++ b/drivers/ide/legacy/hd.c Tue Oct 15 20:29:11 2002 @@ -677,21 +677,11 @@ } } -static int hd_open(struct inode * inode, struct file * filp) -{ - int target = DEVICE_NR(inode->i_rdev); - if (target >= NR_HD) - return -ENODEV; - return 0; -} - /* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */ -extern struct block_device_operations hd_fops; - static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { void (*handler)(void) = do_hd; @@ -705,7 +695,6 @@ } static struct block_device_operations hd_fops = { - .open = hd_open, .ioctl = hd_ioctl, }; @@ -802,12 +791,11 @@ goto out; for (drive=0 ; drive < NR_HD ; drive++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(64); if (!disk) goto Enomem; disk->major = MAJOR_NR; disk->first_minor = drive << 6; - disk->minor_shift = 6; disk->fops = &hd_fops; sprintf(disk->disk_name, "hd%c", 'a'+drive); hd_gendisk[drive] = disk; diff -Nru a/drivers/ieee1394/cmp.c b/drivers/ieee1394/cmp.c --- a/drivers/ieee1394/cmp.c Tue Oct 15 20:29:13 2002 +++ b/drivers/ieee1394/cmp.c Tue Oct 15 20:29:13 2002 @@ -199,7 +199,7 @@ } static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf, - u64 addr, unsigned int length) + u64 addr, unsigned int length, u16 flags) { int csraddr = addr - CSR_REGISTER_BASE; int plug; @@ -235,7 +235,7 @@ } static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, - u64 addr, quadlet_t data, quadlet_t arg, int extcode) + u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags) { int csraddr = addr - CSR_REGISTER_BASE; int plug; diff -Nru a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c --- a/drivers/ieee1394/csr.c Tue Oct 15 20:29:13 2002 +++ b/drivers/ieee1394/csr.c Tue Oct 15 20:29:13 2002 @@ -4,20 +4,33 @@ * 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 "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; -/* FIXME: this one won't work on little endian with big endian data */ static u16 csr_crc16(unsigned *data, int length) { int check=0, i; @@ -25,7 +38,7 @@ for (i = length; i; i--) { for (next = check, shift = 28; shift >= 0; shift -= 4 ) { - sum = ((next >> 12) ^ (*data >> shift)) & 0xf; + sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf; next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); } check = next & 0xffff; @@ -60,6 +73,8 @@ | 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)); @@ -71,7 +86,7 @@ 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; @@ -84,13 +99,52 @@ host->csr.channels_available_lo = ~0; } +int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, + size_t size, unsigned char rom_version) +{ + int ret,flags; + 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) +{ + int ret,flags; + 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, unsigned int length) + u64 addr, unsigned int length, u16 fl) { int csraddr = addr - CSR_REGISTER_BASE; const char *src; + int flags; + + spin_lock_irqsave(&host->csr.lock, flags); if (csraddr < CSR_TOPOLOGY_MAP) { if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) { @@ -105,6 +159,7 @@ } memcpy(buffer, src, length); + spin_unlock_irqrestore(&host->csr.lock, flags); return RCODE_COMPLETE; } @@ -112,7 +167,7 @@ #define out if (--length == 0) break static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf, - u64 addr, unsigned int length) + u64 addr, unsigned int length, u16 flags) { int csraddr = addr - CSR_REGISTER_BASE; int oldcycle; @@ -222,7 +277,7 @@ } static int write_regs(struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, unsigned int length) + quadlet_t *data, u64 addr, unsigned int length, u16 flags) { int csraddr = addr - CSR_REGISTER_BASE; @@ -302,7 +357,7 @@ static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store, - u64 addr, quadlet_t data, quadlet_t arg, int extcode) + u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl) { int csraddr = addr - CSR_REGISTER_BASE; unsigned long flags; @@ -379,7 +434,7 @@ } static int write_fcp(struct hpsb_host *host, int nodeid, int dest, - quadlet_t *data, u64 addr, unsigned int length) + quadlet_t *data, u64 addr, unsigned int length, u16 flags) { int csraddr = addr - CSR_REGISTER_BASE; @@ -436,9 +491,11 @@ hpsb_register_addrspace(hl, &map_ops, CSR_REGISTER_BASE + CSR_CONFIG_ROM, CSR_REGISTER_BASE + CSR_CONFIG_ROM_END); - hpsb_register_addrspace(hl, &fcp_ops, + if (fcp) { + hpsb_register_addrspace(hl, &fcp_ops, CSR_REGISTER_BASE + CSR_FCP_COMMAND, CSR_REGISTER_BASE + CSR_FCP_END); + } hpsb_register_addrspace(hl, &map_ops, CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP, CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END); diff -Nru a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h --- a/drivers/ieee1394/csr.h Tue Oct 15 20:29:12 2002 +++ b/drivers/ieee1394/csr.h Tue Oct 15 20:29:12 2002 @@ -41,8 +41,10 @@ quadlet_t bandwidth_available; quadlet_t channels_available_hi, channels_available_lo; - const quadlet_t *rom; + quadlet_t *rom; size_t rom_size; + unsigned char rom_version; + quadlet_t topology_map[256]; quadlet_t speed_map[1024]; diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c --- a/drivers/ieee1394/dv1394.c Tue Oct 15 20:29:19 2002 +++ b/drivers/ieee1394/dv1394.c Tue Oct 15 20:29:19 2002 @@ -97,7 +97,6 @@ #include #include #include -#include #include #include #include @@ -2587,6 +2586,7 @@ return p; } +#ifdef CONFIG_DEVFS_FS static int dv1394_devfs_add_entry(struct video_card *video) { char buf[32]; @@ -2694,6 +2694,7 @@ kfree(p); } } +#endif /* CONFIG_DEVFS_FS */ /*** IEEE1394 HPSB CALLBACKS ***********************************************/ @@ -2852,7 +2853,6 @@ { struct ti_ohci *ohci; char buf[16]; - struct dv1394_devfs_entry *devfs_entry; /* We only work with the OHCI-1394 driver */ if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) @@ -2874,13 +2874,15 @@ #endif #ifdef CONFIG_DEVFS_FS - devfs_entry = dv1394_devfs_find("dv"); +{ + 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); diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c --- a/drivers/ieee1394/eth1394.c Tue Oct 15 20:29:12 2002 +++ b/drivers/ieee1394/eth1394.c Tue Oct 15 20:29:12 2002 @@ -77,7 +77,7 @@ printk(KERN_ERR fmt, ## args) static char version[] __devinitdata = - "$Rev: 546 $ Ben Collins "; + "$Rev: 601 $ Ben Collins "; /* Our ieee1394 highlevel driver */ #define ETHER1394_DRIVER_NAME "ether1394" @@ -522,7 +522,7 @@ * ethernet header, and fill it with some of our other fields. This is * an incoming packet from the 1394 bus. */ static int ether1394_write (struct hpsb_host *host, int srcid, int destid, - quadlet_t *data, u64 addr, unsigned int len) + quadlet_t *data, u64 addr, unsigned int len, u16 fl) { struct sk_buff *skb; char *buf = (char *)data; @@ -682,8 +682,8 @@ ptask->skb = skb; ptask->addr = addr; ptask->dest_node = dest_node; - INIT_TQUEUE(&ptask->tq, hpsb_write_sched, ptask); - schedule_task(&ptask->tq); + HPSB_INIT_WORK(&ptask->tq, hpsb_write_sched, ptask); + hpsb_schedule_work(&ptask->tq); return 0; fail: diff -Nru a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h --- a/drivers/ieee1394/eth1394.h Tue Oct 15 20:29:21 2002 +++ b/drivers/ieee1394/eth1394.h Tue Oct 15 20:29:21 2002 @@ -56,7 +56,7 @@ struct sk_buff *skb; /* Socket buffer we are sending */ nodeid_t dest_node; /* Destination of the packet */ u64 addr; /* Address */ - struct tq_struct tq; /* The task */ + struct hpsb_queue_struct tq; /* The task */ }; /* IP1394 headers */ diff -Nru a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c --- a/drivers/ieee1394/highlevel.c Tue Oct 15 20:29:20 2002 +++ b/drivers/ieee1394/highlevel.c Tue Oct 15 20:29:20 2002 @@ -5,6 +5,16 @@ * * 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 @@ -129,6 +139,32 @@ return retval; } +int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start) +{ + int retval = 0; + struct hpsb_address_serve *as; + struct list_head *entry; + + write_lock_irq(&addr_space_lock); + + 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_irq(&addr_space_lock); + + return retval; +} void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned int channel) @@ -243,7 +279,7 @@ } int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer, - u64 addr, unsigned int length) + u64 addr, unsigned int length, u16 flags) { struct hpsb_address_serve *as; struct list_head *entry; @@ -261,7 +297,7 @@ if (as->op->read != NULL) { rcode = as->op->read(host, nodeid, buffer, - addr, partlength); + addr, partlength, flags); } else { rcode = RCODE_TYPE_ERROR; } @@ -288,7 +324,7 @@ } int highlevel_write(struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, unsigned int length) + quadlet_t *data, u64 addr, unsigned int length, u16 flags) { struct hpsb_address_serve *as; struct list_head *entry; @@ -306,7 +342,7 @@ if (as->op->write != NULL) { rcode = as->op->write(host, nodeid, destid, - data, addr, partlength); + data, addr, partlength, flags); } else { rcode = RCODE_TYPE_ERROR; } @@ -334,7 +370,7 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, - u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode) + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags) { struct hpsb_address_serve *as; struct list_head *entry; @@ -349,7 +385,7 @@ if (as->end > addr) { if (as->op->lock != NULL) { rcode = as->op->lock(host, nodeid, store, addr, - data, arg, ext_tcode); + data, arg, ext_tcode, flags); } else { rcode = RCODE_TYPE_ERROR; } @@ -367,7 +403,7 @@ } int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, - u64 addr, octlet_t data, octlet_t arg, int ext_tcode) + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags) { struct hpsb_address_serve *as; struct list_head *entry; @@ -383,7 +419,7 @@ if (as->op->lock64 != NULL) { rcode = as->op->lock64(host, nodeid, store, addr, data, arg, - ext_tcode); + ext_tcode, flags); } else { rcode = RCODE_TYPE_ERROR; } diff -Nru a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h --- a/drivers/ieee1394/highlevel.h Tue Oct 15 20:29:16 2002 +++ b/drivers/ieee1394/highlevel.h Tue Oct 15 20:29:16 2002 @@ -74,17 +74,22 @@ */ /* 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, unsigned int length); + u64 addr, unsigned int length, u16 flags); int (*write) (struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, unsigned int length); + quadlet_t *data, u64 addr, unsigned int 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); + 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); + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); }; @@ -94,14 +99,23 @@ 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, quadlet_t *buffer, - u64 addr, unsigned int length); + u64 addr, unsigned int length, u16 flags); int highlevel_write(struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, unsigned int length); + quadlet_t *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); + 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); + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data, unsigned int length); @@ -129,6 +143,8 @@ */ 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 diff -Nru a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c --- a/drivers/ieee1394/hosts.c Tue Oct 15 20:29:16 2002 +++ b/drivers/ieee1394/hosts.c Tue Oct 15 20:29:16 2002 @@ -138,7 +138,7 @@ atomic_set(&h->generation, 0); - INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); + HPSB_INIT_WORK(&h->timeout_tq, (void (*)(void*))abort_timedouts, h); h->topology_map = h->csr.topology_map + 3; h->speed_map = (u8 *)(h->csr.speed_map + 2); diff -Nru a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h --- a/drivers/ieee1394/hosts.h Tue Oct 15 20:29:12 2002 +++ b/drivers/ieee1394/hosts.h Tue Oct 15 20:29:12 2002 @@ -2,13 +2,20 @@ #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; @@ -23,7 +30,7 @@ struct list_head pending_packets; spinlock_t pending_pkt_lock; - struct tq_struct timeout_tq; + struct hpsb_queue_struct timeout_tq; /* A bitmask where a set bit means that this tlabel is in use. * FIXME - should be handled per node instead of per bus. */ @@ -119,7 +126,7 @@ * may not fail. If any allocation is required, it must be done * earlier. */ - size_t (*get_rom) (struct hpsb_host *host, const quadlet_t **pointer); + 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 @@ -171,5 +178,25 @@ 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 -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c --- a/drivers/ieee1394/ieee1394_core.c Tue Oct 15 20:29:14 2002 +++ b/drivers/ieee1394/ieee1394_core.c Tue Oct 15 20:29:14 2002 @@ -5,9 +5,19 @@ * 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 @@ -19,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -72,9 +81,10 @@ struct list_head *lh, *next; list_for_each_safe(lh, next, &packet->complete_tq) { - struct tq_struct *tq = list_entry(lh, struct tq_struct, list); - list_del(&tq->list); - schedule_task(tq); + struct hpsb_queue_struct *tq = + list_entry(lh, struct hpsb_queue_struct, hpsb_queue_list); + list_del(&tq->hpsb_queue_list); + hpsb_schedule_work(tq); } return; @@ -83,11 +93,11 @@ /** * hpsb_add_packet_complete_task - add a new task for when a packet completes * @packet: the packet whose completion we want the task added to - * @tq: the tq_struct describing the task to add + * @tq: the hpsb_queue_struct describing the task to add */ -void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq) +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq) { - list_add_tail(&tq->list, &packet->complete_tq); + list_add_tail(&tq->hpsb_queue_list, &packet->complete_tq); return; } @@ -372,12 +382,19 @@ build_speed_map(host, host->node_count); } +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + HPSB_INFO("selfid_complete called with successful SelfID stage " + "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id); +#endif /* irm_id is kept up to date by check_selfids() */ if (host->irm_id == host->node_id) { host->is_irm = 1; host->is_busmgr = 1; host->busmgr_id = host->node_id; host->csr.bus_manager_id = host->node_id; + } else { + host->is_busmgr = 0; + host->is_irm = 0; } host->reset_retries = 0; @@ -420,7 +437,7 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); up(&packet->state_change); - schedule_task(&host->timeout_tq); + hpsb_schedule_work(&host->timeout_tq); } /** @@ -448,6 +465,45 @@ 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; + + int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + data = kmalloc(packet->header_size + packet->data_size, kmflags); + 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]); + } + } + } + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + dump_packet("send packet local:", packet->header, + packet->header_size); +#endif + 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[(host->node_id & NODE_MASK) * 64 @@ -600,8 +656,10 @@ { struct hpsb_packet *packet; int length, rcode, extcode; + quadlet_t buffer; nodeid_t source = data[1] >> 16; - nodeid_t dest = data[0] >> 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 */ @@ -610,10 +668,11 @@ case TCODE_WRITEQ: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_write(host, source, dest, data+3, - addr, 4); + addr, 4, flags); if (!write_acked - && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) { + && (((data[0] >> 16) & NODE_MASK) != NODE_MASK) + && (rcode >= 0)) { /* not a broadcast write, reply */ PREP_REPLY_PACKET(0); fill_async_write_resp(packet, rcode); @@ -624,10 +683,11 @@ case TCODE_WRITEB: addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_write(host, source, dest, data+4, - addr, data[3]>>16); + addr, data[3]>>16, flags); if (!write_acked - && ((data[0] >> 16) & NODE_MASK) != NODE_MASK) { + && (((data[0] >> 16) & NODE_MASK) != NODE_MASK) + && (rcode >= 0)) { /* not a broadcast write, reply */ PREP_REPLY_PACKET(0); fill_async_write_resp(packet, rcode); @@ -636,12 +696,14 @@ break; case TCODE_READQ: - PREP_REPLY_PACKET(0); - addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; - rcode = highlevel_read(host, source, data, addr, 4); - fill_async_readquad_resp(packet, rcode, *data); - send_packet_nocare(packet); + 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: @@ -650,9 +712,12 @@ addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; rcode = highlevel_read(host, source, packet->data, addr, - length); - fill_async_readblock_resp(packet, rcode, length); - send_packet_nocare(packet); + length, flags); + + if (rcode >= 0) { + fill_async_readblock_resp(packet, rcode, length); + send_packet_nocare(packet); + } break; case TCODE_LOCK_REQUEST: @@ -670,7 +735,7 @@ switch (length) { case 4: rcode = highlevel_lock(host, source, packet->data, addr, - data[4], 0, extcode); + data[4], 0, extcode,flags); fill_async_lock_resp(packet, rcode, extcode, 4); break; case 8: @@ -679,13 +744,13 @@ rcode = highlevel_lock(host, source, packet->data, addr, data[5], data[4], - extcode); + 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); + extcode, flags); fill_async_lock_resp(packet, rcode, extcode, 8); } break; @@ -694,15 +759,20 @@ (octlet_t *)packet->data, addr, *(octlet_t *)(data + 6), *(octlet_t *)(data + 4), - extcode); + extcode, flags); fill_async_lock_resp(packet, rcode, extcode, 8); break; default: - fill_async_lock_resp(packet, RCODE_TYPE_ERROR, + rcode = RCODE_TYPE_ERROR; + fill_async_lock_resp(packet, rcode, extcode, 0); } - send_packet_nocare(packet); + if (rcode >= 0) { + send_packet_nocare(packet); + } else { + free_hpsb_packet(packet); + } break; } @@ -811,7 +881,7 @@ } if (!list_empty(&host->pending_packets)) - schedule_task(&host->timeout_tq); + hpsb_schedule_work(&host->timeout_tq); spin_unlock_irqrestore(&host->pending_pkt_lock, flags); @@ -1109,6 +1179,7 @@ EXPORT_SYMBOL(hpsb_make_writeqpacket); EXPORT_SYMBOL(hpsb_make_writebpacket); EXPORT_SYMBOL(hpsb_make_lockpacket); +EXPORT_SYMBOL(hpsb_make_lock64packet); EXPORT_SYMBOL(hpsb_make_phypacket); EXPORT_SYMBOL(hpsb_packet_success); EXPORT_SYMBOL(hpsb_make_packet); @@ -1119,6 +1190,7 @@ 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(highlevel_read); @@ -1135,6 +1207,8 @@ EXPORT_SYMBOL(hpsb_node_read); EXPORT_SYMBOL(hpsb_node_write); EXPORT_SYMBOL(hpsb_node_lock); +EXPORT_SYMBOL(hpsb_update_config_rom); +EXPORT_SYMBOL(hpsb_get_config_rom); EXPORT_SYMBOL(hpsb_register_protocol); EXPORT_SYMBOL(hpsb_unregister_protocol); EXPORT_SYMBOL(hpsb_release_unit_directory); diff -Nru a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h --- a/drivers/ieee1394/ieee1394_core.h Tue Oct 15 20:29:12 2002 +++ b/drivers/ieee1394/ieee1394_core.h Tue Oct 15 20:29:12 2002 @@ -2,7 +2,6 @@ #ifndef _IEEE1394_CORE_H #define _IEEE1394_CORE_H -#include #include #include #include @@ -78,7 +77,7 @@ }; /* add a new task for when a packet completes */ -void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct tq_struct *tq); +void hpsb_add_packet_complete_task(struct hpsb_packet *packet, struct hpsb_queue_struct *tq); static inline struct hpsb_packet *driver_packet(struct list_head *l) { diff -Nru a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c --- a/drivers/ieee1394/ieee1394_transactions.c Tue Oct 15 20:29:15 2002 +++ b/drivers/ieee1394/ieee1394_transactions.c Tue Oct 15 20:29:15 2002 @@ -297,14 +297,6 @@ HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__); } - -int hpsb_read_trylocal(struct hpsb_host *host, nodeid_t node, u64 addr, - quadlet_t *buffer, size_t length) -{ - if (host->node_id != node) return -1; - return highlevel_read(host, node, buffer, addr, length); -} - struct hpsb_packet *hpsb_make_readqpacket(struct hpsb_host *host, nodeid_t node, u64 addr) { @@ -400,6 +392,31 @@ return p; } +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(16); + if (!p) return NULL; + + p->host = host; + p->tlabel = get_tlabel(host, node, 1); + p->node_id = node; + + switch (extcode) { + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + fill_async_lock(p, addr, extcode, 8); + break; + default: + fill_async_lock(p, addr, extcode, 16); + break; + } + + return p; +} + struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data) { @@ -429,18 +446,6 @@ return -EINVAL; } - if (host->node_id == node) { - switch(highlevel_read(host, node, buffer, addr, length)) { - case RCODE_COMPLETE: - return 0; - case RCODE_TYPE_ERROR: - return -EACCES; - case RCODE_ADDRESS_ERROR: - default: - return -EINVAL; - } - } - if (length == 4) { packet = hpsb_make_readqpacket(host, node, addr); } else { @@ -509,18 +514,6 @@ if (length == 0) return -EINVAL; - if (host->node_id == node) { - switch(highlevel_write(host, node, node, buffer, addr, length)) { - case RCODE_COMPLETE: - return 0; - case RCODE_TYPE_ERROR: - return -EACCES; - case RCODE_ADDRESS_ERROR: - default: - return -EINVAL; - } - } - packet = hpsb_make_packet (host, node, addr, buffer, length); if (!packet) @@ -551,19 +544,6 @@ struct hpsb_packet *packet; int retval = 0, length; - if (host->node_id == node) { - switch(highlevel_lock(host, node, data, addr, *data, arg, - extcode)) { - case RCODE_COMPLETE: - return 0; - case RCODE_TYPE_ERROR: - return -EACCES; - case RCODE_ADDRESS_ERROR: - default: - return -EINVAL; - } - } - packet = alloc_hpsb_packet(8); if (!packet) { return -ENOMEM; diff -Nru a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h --- a/drivers/ieee1394/ieee1394_transactions.h Tue Oct 15 20:29:15 2002 +++ b/drivers/ieee1394/ieee1394_transactions.h Tue Oct 15 20:29:15 2002 @@ -42,6 +42,8 @@ size_t length); struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode); +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode); struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data) ; diff -Nru a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h --- a/drivers/ieee1394/ieee1394_types.h Tue Oct 15 20:29:19 2002 +++ b/drivers/ieee1394/ieee1394_types.h Tue Oct 15 20:29:19 2002 @@ -20,23 +20,6 @@ #define __devexit_p(x) x #endif -/* This showed up around this time */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,12) - -# ifndef MODULE_LICENSE -# define MODULE_LICENSE(x) -# endif - -# ifndef min -# define min(x,y) ({ \ - const typeof(x) _x = (x); \ - const typeof(y) _y = (y); \ - (void) (&_x == &_y); \ - _x < _y ? _x : _y; }) -# endif - -#endif /* Linux version < 2.4.12 */ - #include #ifndef list_for_each_safe @@ -58,9 +41,34 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) #endif + +/* Compatibility for task/work queues */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,42) +/* Use task queue */ +#include +#define hpsb_queue_struct tq_struct +#define hpsb_queue_list list +#define hpsb_schedule_work(x) schedule_task(x) +#define HPSB_INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z) +#define HPSB_PREPARE_WORK(x,y,z) PREPARE_TQUEUE(x,y,z) +#else +/* Use work queue */ +#include +#define hpsb_queue_struct work_struct +#define hpsb_queue_list entry +#define hpsb_schedule_work(x) schedule_work(x) +#define HPSB_INIT_WORK(x,y,z) INIT_WORK(x,y,z) +#define HPSB_PREPARE_WORK(x,y,z) PREPARE_WORK(x,y,z) +#endif + + 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 NODE_MASK 0x003f diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c --- a/drivers/ieee1394/ohci1394.c Tue Oct 15 20:29:20 2002 +++ b/drivers/ieee1394/ohci1394.c Tue Oct 15 20:29:20 2002 @@ -91,7 +91,6 @@ #include #include #include -#include #include #include @@ -154,7 +153,7 @@ printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) static char version[] __devinitdata = - "$Rev: 578 $ Ben Collins "; + "$Rev: 601 $ Ben Collins "; /* Module Parameters */ MODULE_PARM(attempt_root,"i"); @@ -1905,7 +1904,7 @@ ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu; } -static size_t ohci_get_rom(struct hpsb_host *host, const quadlet_t **ptr) +static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr) { struct ti_ohci *ohci=host->hostdata; diff -Nru a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c --- a/drivers/ieee1394/pcilynx.c Tue Oct 15 20:29:16 2002 +++ b/drivers/ieee1394/pcilynx.c Tue Oct 15 20:29:16 2002 @@ -1677,7 +1677,7 @@ -static size_t get_lynx_rom(struct hpsb_host *host, const quadlet_t **ptr) +static size_t get_lynx_rom(struct hpsb_host *host, quadlet_t **ptr) { struct ti_lynx *lynx = host->hostdata; *ptr = lynx->config_rom; diff -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c --- a/drivers/ieee1394/raw1394.c Tue Oct 15 20:29:11 2002 +++ b/drivers/ieee1394/raw1394.c Tue Oct 15 20:29:11 2002 @@ -4,9 +4,27 @@ * Raw interface to the bus * * Copyright (C) 1999, 2000 Andreas E. Bombe + * 2001, 2002 Manfred Weihs + * 2002 Christian Toegel * * 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 + * address range mapping + * adaptation for new (transparent) loopback mechanism + * sending of arbitrary async packets + * Christian Toegel + * address range mapping + * lock64 request + * transmit physical packet + * busreset notification control (switch on/off) + * busreset with selection of type (short/long) + * request_reply */ #include @@ -40,6 +58,16 @@ #define ptr2int(x) ((u64)(u32)x) #endif +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#define RAW1394_DEBUG +#endif + +#ifdef RAW1394_DEBUG +#define DBGMSG(fmt, args...) \ +printk(KERN_INFO "raw1394:" fmt "\n" , ## args) +#else +#define DBGMSG(fmt, args...) +#endif static devfs_handle_t devfs_handle; @@ -53,6 +81,21 @@ static atomic_t iso_buffer_size; static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */ +static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length, u16 flags); +static int arm_write (struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length, u16 flags); +static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags); +static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); +static struct hpsb_address_ops arm_ops = { + read: arm_read, + write: arm_write, + lock: arm_lock, + lock64: arm_lock64, +}; + static void queue_complete_cb(struct pending_request *req); static struct pending_request *__alloc_pending_request(int flags) @@ -64,7 +107,7 @@ if (req != NULL) { memset(req, 0, sizeof(struct pending_request)); INIT_LIST_HEAD(&req->list); - INIT_TQUEUE(&req->tq, (void(*)(void*))queue_complete_cb, NULL); + HPSB_INIT_WORK(&req->tq, (void(*)(void*))queue_complete_cb, NULL); } return req; @@ -128,7 +171,8 @@ req->req.length = 0; } - free_tlabel(packet->host, packet->node_id, packet->tlabel); + if (req->req.type != RAW1394_REQ_PHYPACKET) + free_tlabel(packet->host, packet->node_id, packet->tlabel); queue_complete_req(req); } @@ -137,6 +181,7 @@ static void add_host(struct hpsb_host *host) { struct host_info *hi; + unsigned long flags; hi = (struct host_info *)kmalloc(sizeof(struct host_info), SLAB_KERNEL); if (hi != NULL) { @@ -144,10 +189,10 @@ hi->host = host; INIT_LIST_HEAD(&hi->file_info_list); - spin_lock_irq(&host_info_lock); + spin_lock_irqsave(&host_info_lock, flags); list_add_tail(&hi->list, &host_info_list); host_count++; - spin_unlock_irq(&host_info_lock); + spin_unlock_irqrestore(&host_info_lock, flags); } atomic_inc(&internal_generation); @@ -172,15 +217,22 @@ static void remove_host(struct hpsb_host *host) { struct host_info *hi; + unsigned long flags; - spin_lock_irq(&host_info_lock); + spin_lock_irqsave(&host_info_lock, flags); hi = find_host_info(host); if (hi != NULL) { list_del(&hi->list); host_count--; + /* + FIXME: adressranges should be removed + and fileinfo states should be initialized + (including setting generation to + internal-generation ...) + */ } - spin_unlock_irq(&host_info_lock); + spin_unlock_irqrestore(&host_info_lock, flags); if (hi == NULL) { printk(KERN_ERR "raw1394: attempt to remove unknown host " @@ -207,20 +259,22 @@ if (hi != NULL) { list_for_each(lh, &hi->file_info_list) { fi = list_entry(lh, struct file_info, list); - req = __alloc_pending_request(SLAB_ATOMIC); + if (fi->notification == RAW1394_NOTIFY_ON) { + req = __alloc_pending_request(SLAB_ATOMIC); - if (req != NULL) { - req->file_info = fi; - req->req.type = RAW1394_REQ_BUS_RESET; - req->req.generation = get_hpsb_generation(host); - req->req.misc = (host->node_id << 16) - | host->node_count; - if (fi->protocol_version > 3) { - req->req.misc |= ((host->irm_id - & NODE_MASK) << 8); - } + if (req != NULL) { + req->file_info = fi; + req->req.type = RAW1394_REQ_BUS_RESET; + req->req.generation = get_hpsb_generation(host); + req->req.misc = (host->node_id << 16) + | host->node_count; + if (fi->protocol_version > 3) { + req->req.misc |= ((host->irm_id + & NODE_MASK) << 8); + } - queue_complete_req(req); + queue_complete_req(req); + } } } } @@ -529,7 +583,7 @@ { int channel = req->req.misc; - spin_lock(&host_info_lock); + spin_lock_irq(&host_info_lock); if ((channel > 63) || (channel < -64)) { req->req.error = RAW1394_ERROR_INVALID_ARG; } else if (channel >= 0) { @@ -556,7 +610,7 @@ req->req.length = 0; queue_complete_req(req); - spin_unlock(&host_info_lock); + spin_unlock_irq(&host_info_lock); } static void handle_fcp_listen(struct file_info *fi, struct pending_request *req) @@ -579,84 +633,9 @@ queue_complete_req(req); } -static int handle_local_request(struct file_info *fi, - struct pending_request *req, int node) -{ - u64 addr = req->req.address & 0xffffffffffffULL; - - req->data = kmalloc(req->req.length, SLAB_KERNEL); - if (!req->data) return -ENOMEM; - req->free_data = 1; - - switch (req->req.type) { - case RAW1394_REQ_ASYNC_READ: - req->req.error = highlevel_read(fi->host, node, req->data, addr, - req->req.length); - break; - - case RAW1394_REQ_ASYNC_WRITE: - if (copy_from_user(req->data, int2ptr(req->req.sendb), - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - break; - } - - req->req.error = highlevel_write(fi->host, node, node, req->data, - addr, req->req.length); - req->req.length = 0; - break; - case RAW1394_REQ_LOCK: - if ((req->req.misc == EXTCODE_FETCH_ADD) - || (req->req.misc == EXTCODE_LITTLE_ADD)) { - if (req->req.length != 4) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } else { - if (req->req.length != 8) { - req->req.error = RAW1394_ERROR_INVALID_ARG; - break; - } - } - - if (copy_from_user(req->data, int2ptr(req->req.sendb), - req->req.length)) { - req->req.error = RAW1394_ERROR_MEMFAULT; - break; - } - - if (req->req.length == 8) { - req->req.error = highlevel_lock(fi->host, node, - req->data, addr, - req->data[1], - req->data[0], - req->req.misc); - req->req.length = 4; - } else { - req->req.error = highlevel_lock(fi->host, node, - req->data, addr, - req->data[0], 0, - req->req.misc); - } - break; - - case RAW1394_REQ_LOCK64: - default: - req->req.error = RAW1394_ERROR_STATE_ORDER; - } - - if (req->req.error) - req->req.length = 0; - if (req->req.error >= 0) - req->req.error |= ACK_PENDING << 16; - - queue_complete_req(req); - return sizeof(struct raw1394_request); -} - -static int handle_remote_request(struct file_info *fi, - struct pending_request *req, int node) +static int handle_async_request(struct file_info *fi, + struct pending_request *req, int node) { struct hpsb_packet *packet = NULL; u64 addr = req->req.address & 0xffffffffffffULL; @@ -664,11 +643,13 @@ switch (req->req.type) { case RAW1394_REQ_ASYNC_READ: if (req->req.length == 4) { + DBGMSG("quadlet_read_request called"); packet = hpsb_make_readqpacket(fi->host, node, addr); if (!packet) return -ENOMEM; req->data = &packet->header[3]; } else { + DBGMSG("block_read_request called"); packet = hpsb_make_readbpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; @@ -681,6 +662,7 @@ if (req->req.length == 4) { quadlet_t x; + DBGMSG("quadlet_write_request called"); if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -689,6 +671,7 @@ x); if (!packet) return -ENOMEM; } else { + DBGMSG("block_write_request called"); packet = hpsb_make_writebpacket(fi->host, node, addr, req->req.length); if (!packet) return -ENOMEM; @@ -702,6 +685,7 @@ break; case RAW1394_REQ_LOCK: + DBGMSG("lock_request called"); if ((req->req.misc == EXTCODE_FETCH_ADD) || (req->req.misc == EXTCODE_LITTLE_ADD)) { if (req->req.length != 4) { @@ -730,6 +714,33 @@ break; case RAW1394_REQ_LOCK64: + DBGMSG("lock64_request called"); + if ((req->req.misc == EXTCODE_FETCH_ADD) + || (req->req.misc == EXTCODE_LITTLE_ADD)) { + if (req->req.length != 8) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } else { + if (req->req.length != 16) { + req->req.error = RAW1394_ERROR_INVALID_ARG; + break; + } + } + packet = hpsb_make_lock64packet(fi->host, node, addr, + req->req.misc); + if (!packet) return -ENOMEM; + + if (copy_from_user(packet->data, int2ptr(req->req.sendb), + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + break; + } + + req->data = packet->data; + req->req.length = 8; + break; + default: req->req.error = RAW1394_ERROR_STATE_ORDER; } @@ -783,8 +794,7 @@ return sizeof(struct raw1394_request); } - req->tq.data = req; - req->tq.routine = (void (*)(void*))queue_complete_req; + HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req); req->req.length = 0; hpsb_add_packet_complete_task(packet, &req->tq); @@ -803,25 +813,1092 @@ return sizeof(struct raw1394_request); } -static int state_connected(struct file_info *fi, struct pending_request *req) +static int handle_async_send(struct file_info *fi, struct pending_request *req) { - int node = req->req.address >> 48; + struct hpsb_packet *packet; + int header_length = req->req.misc & 0xffff; + int expect_response = req->req.misc >> 16; - req->req.error = RAW1394_ERROR_NONE; + if ((header_length > req->req.length) || + (header_length < 12)) + { + req->req.error = RAW1394_ERROR_INVALID_ARG; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } - if (req->req.type == RAW1394_REQ_ISO_SEND) { - return handle_iso_send(fi, req, node); + packet = alloc_hpsb_packet(req->req.length-header_length); + req->packet = packet; + if (!packet) return -ENOMEM; + + if (copy_from_user(packet->header, int2ptr(req->req.sendb), + header_length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); } - if (req->req.generation != get_hpsb_generation(fi->host)) { - req->req.error = RAW1394_ERROR_GENERATION; - req->req.generation = get_hpsb_generation(fi->host); + if (copy_from_user(packet->data, ((u8*) int2ptr(req->req.sendb)) + header_length, + packet->data_size)) { + req->req.error = RAW1394_ERROR_MEMFAULT; req->req.length = 0; queue_complete_req(req); return sizeof(struct raw1394_request); } + packet->type = hpsb_async; + packet->node_id = packet->header[0] >> 16; + packet->tcode = (packet->header[0] >> 4) & 0xf; + packet->tlabel = (packet->header[0] >> 10) &0x3f; + packet->host = fi->host; + packet->expect_response = expect_response; + packet->header_size=header_length; + packet->data_size=req->req.length-header_length; + + HPSB_PREPARE_WORK(&req->tq, (void (*)(void*))queue_complete_req, req); + req->req.length = 0; + hpsb_add_packet_complete_task(packet, &req->tq); + + spin_lock_irq(&fi->reqlists_lock); + list_add_tail(&req->list, &fi->req_pending); + spin_unlock_irq(&fi->reqlists_lock); + + /* Update the generation of the packet just before sending. */ + packet->generation = get_hpsb_generation(fi->host); + + if (!hpsb_send_packet(packet)) { + req->req.error = RAW1394_ERROR_SEND_ERROR; + queue_complete_req(req); + } + + return sizeof(struct raw1394_request); +} + +static int arm_read (struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, unsigned int length, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1; + struct arm_request_response *arm_req_resp = NULL; + + DBGMSG("arm_read called by node: %X" + "addr: %4.4x %8.8x length: %u", nodeid, + (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + length); + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search address-entry */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+length))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_read addr_entry FOUND"); + } + if (arm_addr->rec_length < length) { + DBGMSG("arm_read blocklength too big -> rcode_data_error"); + rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_READ) { + if (!(arm_addr->client_transactions & ARM_READ)) { + memcpy(buffer,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + length); + DBGMSG("arm_read -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_read -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_READ) { + DBGMSG("arm_read -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_read -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + if (rcode == RCODE_COMPLETE) { + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + length * sizeof(byte_t) + + sizeof (struct arm_request_response); + } else { + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + sizeof (struct arm_request_response); + } + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_read -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_READ & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = NULL; + arm_resp->buffer = NULL; + if (rcode == RCODE_COMPLETE) { + arm_resp->buffer = ((byte_t *)(arm_resp) + + (sizeof(struct arm_response))); + memcpy (arm_resp->buffer, + (arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + length); + arm_resp->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response)); + } + arm_resp->buffer_length = (rcode == RCODE_COMPLETE) ? length : 0; + arm_resp->response_code = rcode; + arm_req->buffer_length = 0; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = 0; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response)); + arm_req_resp->response = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request)); + queue_complete_req(req); + } + spin_unlock(&host_info_lock); + return(rcode); +} + +static int arm_write (struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, unsigned int length, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1, length_conflict=0; + struct arm_request_response *arm_req_resp = NULL; + + DBGMSG("arm_write called by node: %X" + "addr: %4.4x %8.8x length: %u", nodeid, + (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + length); + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search address-entry */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+length))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_write addr_entry FOUND"); + } + if (arm_addr->rec_length < length) { + DBGMSG("arm_write blocklength too big -> rcode_data_error"); + length_conflict = 1; + rcode = RCODE_DATA_ERROR; /* hardware error, data is unavailable */ + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_WRITE) { + if (!(arm_addr->client_transactions & ARM_WRITE)) { + memcpy((arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + data, length); + DBGMSG("arm_write -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_write -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_WRITE) { + DBGMSG("arm_write -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_write -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request my be retried */ + } + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + (length) * sizeof(byte_t) + + sizeof (struct arm_request_response); + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_write -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ( ((length << 16) & (0xFFFF0000)) | (ARM_WRITE & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = ((byte_t *)(arm_resp) + + (sizeof(struct arm_response))); + arm_resp->buffer = NULL; + memcpy (arm_req->buffer, data, length); + arm_req->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response)); + arm_req->buffer_length = length; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = 0; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = destid; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->buffer_length = 0; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response)); + arm_req_resp->response = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request)); + queue_complete_req(req); + } + spin_unlock(&host_info_lock); + return(rcode); +} + +static int arm_lock (struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1; + quadlet_t old, new; + struct arm_request_response *arm_req_resp = NULL; + + if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { + DBGMSG("arm_lock called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X", + nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , be32_to_cpu(data)); + } else { + DBGMSG("arm_lock called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X arg: %8.8X", + nodeid, (u16) ((addr >>32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , be32_to_cpu(data), be32_to_cpu(arg)); + } + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search address-entry */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+sizeof(*store)))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_lock addr_entry FOUND"); + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_LOCK) { + if (!(arm_addr->client_transactions & ARM_LOCK)) { + memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + sizeof(old)); + switch (ext_tcode) { + case (EXTCODE_MASK_SWAP): + new = data | (old & ~arg); + break; + case (EXTCODE_COMPARE_SWAP): + if (old == arg) { + new = data; + } else { + new = old; + } + break; + case (EXTCODE_FETCH_ADD): + new = cpu_to_be32(be32_to_cpu(data) + be32_to_cpu(old)); + break; + case (EXTCODE_LITTLE_ADD): + new = cpu_to_le32(le32_to_cpu(data) + le32_to_cpu(old)); + break; + case (EXTCODE_BOUNDED_ADD): + if (old != arg) { + new = cpu_to_be32(be32_to_cpu(data) + + be32_to_cpu(old)); + } else { + new = old; + } + break; + case (EXTCODE_WRAP_ADD): + if (old != arg) { + new = cpu_to_be32(be32_to_cpu(data) + + be32_to_cpu(old)); + } else { + new = data; + } + break; + default: + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + printk(KERN_ERR "raw1394: arm_lock FAILED " + "ext_tcode not allowed -> rcode_type_error\n"); + break; + } /*switch*/ + if (rcode == -1) { + DBGMSG("arm_lock -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + memcpy (store, &old, sizeof(*store)); + memcpy ((arm_addr->addr_space_buffer)+ + (addr-(arm_addr->start)), + &new, sizeof(*store)); + } + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_lock -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_LOCK) { + DBGMSG("arm_lock -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + DBGMSG("arm_lock -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + 3 * sizeof(*store) + + sizeof (struct arm_request_response); /* maximum */ + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + DBGMSG("arm_lock -> rcode_conflict_error"); + spin_unlock(&host_info_lock); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = ((byte_t *)(arm_resp) + + (sizeof(struct arm_response))); + arm_resp->buffer = ((byte_t *)(arm_req->buffer) + + (2* sizeof(*store))); + if ((ext_tcode == EXTCODE_FETCH_ADD) || + (ext_tcode == EXTCODE_LITTLE_ADD)) { + arm_req->buffer_length = sizeof(*store); + memcpy (arm_req->buffer, &data, sizeof(*store)); + + } else { + arm_req->buffer_length = 2 * sizeof(*store); + memcpy (arm_req->buffer, &arg, sizeof(*store)); + memcpy (((arm_req->buffer) + sizeof(*store)), + &data, sizeof(*store)); + } + if (rcode == RCODE_COMPLETE) { + arm_resp->buffer_length = sizeof(*store); + memcpy (arm_resp->buffer, &old, sizeof(*store)); + } else { + arm_resp->buffer = NULL; + arm_resp->buffer_length = 0; + } + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | + (ARM_LOCK & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = ext_tcode; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response)); + arm_req_resp->response = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request)); + arm_req->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response)); + arm_resp->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response) + + 2* sizeof (*store)); + queue_complete_req(req); + } + spin_unlock(&host_info_lock); + return(rcode); +} + +static int arm_lock64 (struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags) +{ + struct pending_request *req; + struct list_head *lh; + struct host_info *hi; + struct file_info *fi = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + struct arm_request *arm_req = NULL; + struct arm_response *arm_resp = NULL; + int found=0, size=0, rcode=-1; + octlet_t old, new; + struct arm_request_response *arm_req_resp = NULL; + + if (((ext_tcode & 0xFF) == EXTCODE_FETCH_ADD) || + ((ext_tcode & 0xFF) == EXTCODE_LITTLE_ADD)) { + DBGMSG("arm_lock64 called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X ", + nodeid, (u16) ((addr >>32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , + (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(data) & 0xFFFFFFFF)); + } else { + DBGMSG("arm_lock64 called by node: %X " + "addr: %4.4x %8.8x extcode: %2.2X data: %8.8X %8.8X arg: " + "%8.8X %8.8X ", + nodeid, (u16) ((addr >>32) & 0xFFFF), + (u32) (addr & 0xFFFFFFFF), + ext_tcode & 0xFF , + (u32) ((be64_to_cpu(data) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(data) & 0xFFFFFFFF), + (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF), + (u32) (be64_to_cpu(arg) & 0xFFFFFFFF)); + } + spin_lock(&host_info_lock); + hi = find_host_info(host); /* search addressentry in file_info's for host */ + if (hi != NULL) { + list_for_each(lh, &hi->file_info_list) { + fi = list_entry(lh, struct file_info, list); + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if (((arm_addr->start) <= (addr)) && + ((arm_addr->end) >= (addr+sizeof(*store)))) { + found = 1; + break; + } + entry = entry->next; + } + if (found) { + break; + } + } + } + rcode = -1; + if (!found) { + printk(KERN_ERR "raw1394: arm_lock64 FAILED addr_entry not found" + " -> rcode_address_error\n"); + spin_unlock(&host_info_lock); + return (RCODE_ADDRESS_ERROR); + } else { + DBGMSG("arm_lock64 addr_entry FOUND"); + } + if (rcode == -1) { + if (arm_addr->access_rights & ARM_LOCK) { + if (!(arm_addr->client_transactions & ARM_LOCK)) { + memcpy(&old,(arm_addr->addr_space_buffer)+(addr-(arm_addr->start)), + sizeof(old)); + switch (ext_tcode) { + case (EXTCODE_MASK_SWAP): + new = data | (old & ~arg); + break; + case (EXTCODE_COMPARE_SWAP): + if (old == arg) { + new = data; + } else { + new = old; + } + break; + case (EXTCODE_FETCH_ADD): + new = cpu_to_be64(be64_to_cpu(data) + be64_to_cpu(old)); + break; + case (EXTCODE_LITTLE_ADD): + new = cpu_to_le64(le64_to_cpu(data) + le64_to_cpu(old)); + break; + case (EXTCODE_BOUNDED_ADD): + if (old != arg) { + new = cpu_to_be64(be64_to_cpu(data) + + be64_to_cpu(old)); + } else { + new = old; + } + break; + case (EXTCODE_WRAP_ADD): + if (old != arg) { + new = cpu_to_be64(be64_to_cpu(data) + + be64_to_cpu(old)); + } else { + new = data; + } + break; + default: + printk(KERN_ERR "raw1394: arm_lock64 FAILED " + "ext_tcode not allowed -> rcode_type_error\n"); + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + break; + } /*switch*/ + if (rcode == -1) { + DBGMSG("arm_lock64 -> (rcode_complete)"); + rcode = RCODE_COMPLETE; + memcpy (store, &old, sizeof(*store)); + memcpy ((arm_addr->addr_space_buffer)+ + (addr-(arm_addr->start)), + &new, sizeof(*store)); + } + } + } else { + rcode = RCODE_TYPE_ERROR; /* function not allowed */ + DBGMSG("arm_lock64 -> rcode_type_error (access denied)"); + } + } + if (arm_addr->notification_options & ARM_LOCK) { + DBGMSG("arm_lock64 -> entering notification-section"); + req = __alloc_pending_request(SLAB_ATOMIC); + if (!req) { + spin_unlock(&host_info_lock); + DBGMSG("arm_lock64 -> rcode_conflict_error"); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + size = sizeof(struct arm_request)+sizeof(struct arm_response) + + 3 * sizeof(*store) + + sizeof (struct arm_request_response); /* maximum */ + req->data = kmalloc(size, SLAB_ATOMIC); + if (!(req->data)) { + free_pending_request(req); + spin_unlock(&host_info_lock); + DBGMSG("arm_lock64 -> rcode_conflict_error"); + return(RCODE_CONFLICT_ERROR); /* A resource conflict was detected. + The request may be retried */ + } + req->free_data=1; + arm_req_resp = (struct arm_request_response *) (req->data); + arm_req = (struct arm_request *) ((byte_t *)(req->data) + + (sizeof (struct arm_request_response))); + arm_resp = (struct arm_response *) ((byte_t *)(arm_req) + + (sizeof(struct arm_request))); + arm_req->buffer = ((byte_t *)(arm_resp) + + (sizeof(struct arm_response))); + arm_resp->buffer = ((byte_t *)(arm_req->buffer) + + (2* sizeof(*store))); + if ((ext_tcode == EXTCODE_FETCH_ADD) || + (ext_tcode == EXTCODE_LITTLE_ADD)) { + arm_req->buffer_length = sizeof(*store); + memcpy (arm_req->buffer, &data, sizeof(*store)); + + } else { + arm_req->buffer_length = 2 * sizeof(*store); + memcpy (arm_req->buffer, &arg, sizeof(*store)); + memcpy (((arm_req->buffer) + sizeof(*store)), + &data, sizeof(*store)); + } + if (rcode == RCODE_COMPLETE) { + arm_resp->buffer_length = sizeof(*store); + memcpy (arm_resp->buffer, &old, sizeof(*store)); + } else { + arm_resp->buffer = NULL; + arm_resp->buffer_length = 0; + } + req->file_info = fi; + req->req.type = RAW1394_REQ_ARM; + req->req.generation = get_hpsb_generation(host); + req->req.misc = ( (((sizeof(*store)) << 16) & (0xFFFF0000)) | + (ARM_LOCK & 0xFF)); + req->req.tag = arm_addr->arm_tag; + req->req.recvb = arm_addr->recvb; + req->req.length = size; + arm_req->generation = req->req.generation; + arm_req->extended_transaction_code = ext_tcode; + arm_req->destination_offset = addr; + arm_req->source_nodeid = nodeid; + arm_req->destination_nodeid = host->node_id; + arm_req->tlabel = (flags >> 10) & 0x3f; + arm_req->tcode = (flags >> 4) & 0x0f; + arm_resp->response_code = rcode; + arm_req_resp->request = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response)); + arm_req_resp->response = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request)); + arm_req->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response)); + arm_resp->buffer = int2ptr((arm_addr->recvb) + + sizeof (struct arm_request_response) + + sizeof (struct arm_request) + + sizeof (struct arm_response) + + 2* sizeof (*store)); + queue_complete_req(req); + } + spin_unlock(&host_info_lock); + return(rcode); +} + +static int arm_register(struct file_info *fi, struct pending_request *req) +{ + int retval; + struct arm_addr *addr; + struct list_head *lh, *lh_1, *lh_2; + struct host_info *hi; + struct file_info *fi_hlp = NULL; + struct list_head *entry; + struct arm_addr *arm_addr = NULL; + int same_host, another_host; + unsigned long flags; + + DBGMSG("arm_register called " + "addr(Offset): %8.8x %8.8x length: %u " + "rights: %2.2X notify: %2.2X " + "max_blk_len: %4.4X", + (u32) ((req->req.address >>32) & 0xFFFF), + (u32) (req->req.address & 0xFFFFFFFF), + req->req.length, ((req->req.misc >> 8) & 0xFF), + (req->req.misc & 0xFF),((req->req.misc >> 16) & 0xFFFF)); + /* check addressrange */ + if ((((req->req.address) & ~(0xFFFFFFFFFFFF)) != 0) || + (((req->req.address + req->req.length) & ~(0xFFFFFFFFFFFF)) != 0)) { + req->req.length = 0; + return (-EINVAL); + } + /* addr-list-entry for fileinfo */ + addr = (struct arm_addr *)kmalloc(sizeof(struct arm_addr), SLAB_KERNEL); + if (!addr) { + req->req.length = 0; + return (-ENOMEM); + } + /* allocation of addr_space_buffer */ + addr->addr_space_buffer = (u8 *)kmalloc(req->req.length,SLAB_KERNEL); + if (!(addr->addr_space_buffer)) { + kfree(addr); + req->req.length = 0; + return (-ENOMEM); + } + /* initialization of addr_space_buffer */ + if ((req->req.sendb)== (unsigned long)NULL) { + /* init: set 0 */ + memset(addr->addr_space_buffer, 0,req->req.length); + } else { + /* init: user -> kernel */ + if (copy_from_user(addr->addr_space_buffer,int2ptr(req->req.sendb), + req->req.length)) { + kfree(addr->addr_space_buffer); + kfree(addr); + return (-EFAULT); + } + } + INIT_LIST_HEAD(&addr->addr_list); + addr->arm_tag = req->req.tag; + addr->start = req->req.address; + addr->end = req->req.address + req->req.length; + addr->access_rights = (u8) (req->req.misc & 0x0F); + addr->notification_options = (u8) ((req->req.misc >> 4) & 0x0F); + addr->client_transactions = (u8) ((req->req.misc >> 8) & 0x0F); + addr->access_rights |= addr->client_transactions; + addr->notification_options |= addr->client_transactions; + addr->recvb = req->req.recvb; + addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF); + spin_lock_irqsave(&host_info_lock, flags); + hi = find_host_info(fi->host); + same_host = 0; + another_host = 0; + /* same host with address-entry containing same addressrange ? */ + list_for_each(lh, &hi->file_info_list) { + fi_hlp = list_entry(lh, struct file_info, list); + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if ( (arm_addr->start == addr->start) && + (arm_addr->end == addr->end)) { + DBGMSG("same host ownes same " + "addressrange -> EALREADY"); + same_host = 1; + break; + } + entry = entry->next; + } + if (same_host) { + break; + } + } + if (same_host) { + /* addressrange occupied by same host */ + kfree(addr->addr_space_buffer); + kfree(addr); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EALREADY); + } + /* another host with valid address-entry containing same addressrange */ + list_for_each(lh_1, &host_info_list) { + hi = list_entry(lh_1, struct host_info, list); + if (hi->host != fi->host) { + list_for_each(lh_2, &hi->file_info_list) { + fi_hlp = list_entry(lh_2, struct file_info, list); + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = list_entry(entry, struct arm_addr, addr_list); + if ( (arm_addr->start == addr->start) && + (arm_addr->end == addr->end)) { + DBGMSG("another host ownes same " + "addressrange"); + another_host = 1; + break; + } + entry = entry->next; + } + if (another_host) { + break; + } + } + } + } + if (another_host) { + DBGMSG("another hosts entry is valid -> SUCCESS"); + if (copy_to_user(int2ptr(req->req.recvb), + int2ptr(&addr->start),sizeof(u64))) { + printk(KERN_ERR "raw1394: arm_register failed " + " address-range-entry is invalid -> EFAULT !!!\n"); + kfree(addr->addr_space_buffer); + kfree(addr); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EFAULT); + } + free_pending_request(req); /* immediate success or fail */ + /* INSERT ENTRY */ + list_add_tail(&addr->addr_list, &fi->addr_list); + spin_unlock_irqrestore(&host_info_lock, flags); + return sizeof(struct raw1394_request); + } + retval = hpsb_register_addrspace(hl_handle, &arm_ops, req->req.address, + req->req.address + req->req.length); + if (retval) { + /* INSERT ENTRY */ + list_add_tail(&addr->addr_list, &fi->addr_list); + } else { + DBGMSG("arm_register failed errno: %d \n",retval); + kfree(addr->addr_space_buffer); + kfree(addr); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EALREADY); + } + spin_unlock_irqrestore(&host_info_lock, flags); + free_pending_request(req); /* immediate success or fail */ + return sizeof(struct raw1394_request); +} + +static int arm_unregister(struct file_info *fi, struct pending_request *req) +{ + int found = 0; + int retval = 0; + struct list_head *entry; + struct arm_addr *addr = NULL; + struct list_head *lh_1, *lh_2; + struct host_info *hi; + struct file_info *fi_hlp = NULL; + struct arm_addr *arm_addr = NULL; + int another_host; + unsigned long flags; + + DBGMSG("arm_Unregister called addr(Offset): " + "%8.8x %8.8x", + (u32) ((req->req.address >>32) & 0xFFFF), + (u32) (req->req.address & 0xFFFFFFFF)); + spin_lock_irqsave(&host_info_lock, flags); + /* get addr */ + entry = fi->addr_list.next; + while (entry != &(fi->addr_list)) { + addr = list_entry(entry, struct arm_addr, addr_list); + if (addr->start == req->req.address) { + found = 1; + break; + } + entry = entry->next; + } + if (!found) { + DBGMSG("arm_Unregister addr not found"); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EINVAL); + } + DBGMSG("arm_Unregister addr found"); + another_host = 0; + /* another host with valid address-entry containing + same addressrange */ + list_for_each(lh_1, &host_info_list) { + hi = list_entry(lh_1, struct host_info, list); + if (hi->host != fi->host) { + list_for_each(lh_2, &hi->file_info_list) { + fi_hlp = list_entry(lh_2, struct file_info, list); + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = list_entry(entry, + struct arm_addr, addr_list); + if (arm_addr->start == + addr->start) { + DBGMSG("another host ownes " + "same addressrange"); + another_host = 1; + break; + } + entry = entry->next; + } + if (another_host) { + break; + } + } + } + } + if (another_host) { + DBGMSG("delete entry from list -> success"); + list_del(&addr->addr_list); + kfree(addr->addr_space_buffer); + kfree(addr); + free_pending_request(req); /* immediate success or fail */ + spin_unlock_irqrestore(&host_info_lock, flags); + return sizeof(struct raw1394_request); + } + retval = hpsb_unregister_addrspace(hl_handle, addr->start); + if (!retval) { + printk(KERN_ERR "raw1394: arm_Unregister failed -> EINVAL\n"); + spin_unlock_irqrestore(&host_info_lock, flags); + return (-EINVAL); + } + DBGMSG("delete entry from list -> success"); + list_del(&addr->addr_list); + spin_unlock_irqrestore(&host_info_lock, flags); + kfree(addr->addr_space_buffer); + kfree(addr); + free_pending_request(req); /* immediate success or fail */ + return sizeof(struct raw1394_request); +} + +static int reset_notification(struct file_info *fi, struct pending_request *req) +{ + DBGMSG("reset_notification called - switch %s ", + (req->req.misc == RAW1394_NOTIFY_OFF)?"OFF":"ON"); + if ((req->req.misc == RAW1394_NOTIFY_OFF) || + (req->req.misc == RAW1394_NOTIFY_ON)) { + fi->notification=(u8)req->req.misc; + free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ + return sizeof(struct raw1394_request); + } + /* error EINVAL (22) invalid argument */ + return (-EINVAL); +} + +static int write_phypacket(struct file_info *fi, struct pending_request *req) +{ + struct hpsb_packet *packet = NULL; + int retval=0; + quadlet_t data; + + data = be32_to_cpu((u32)req->req.sendb); + DBGMSG("write_phypacket called - quadlet 0x%8.8x ",data); + packet = hpsb_make_phypacket (fi->host, data); + if (!packet) return -ENOMEM; + req->req.length=0; + req->packet=packet; + req->tq.data=req; + hpsb_add_packet_complete_task(packet, &req->tq); + spin_lock_irq(&fi->reqlists_lock); + list_add_tail(&req->list, &fi->req_pending); + spin_unlock_irq(&fi->reqlists_lock); + packet->generation = req->req.generation; + retval = hpsb_send_packet(packet); + DBGMSG("write_phypacket send_packet called => retval: %d ", + retval); + if (! retval) { + req->req.error = RAW1394_ERROR_SEND_ERROR; + req->req.length = 0; + queue_complete_req(req); + } + return sizeof(struct raw1394_request); +} + +static int get_config_rom(struct file_info *fi, struct pending_request *req) +{ + size_t return_size; + unsigned char rom_version; + int ret=sizeof(struct raw1394_request); + quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL); + int status; + if (!data) return -ENOMEM; + status = hpsb_get_config_rom(fi->host, data, + req->req.length, &return_size, &rom_version); + if (copy_to_user(int2ptr(req->req.recvb), data, + req->req.length)) + ret = -EFAULT; + if (copy_to_user(int2ptr(req->req.tag), &return_size, + sizeof(return_size))) + ret = -EFAULT; + if (copy_to_user(int2ptr(req->req.address), &rom_version, + sizeof(rom_version))) + ret = -EFAULT; + if (copy_to_user(int2ptr(req->req.sendb), &status, + sizeof(status))) + ret = -EFAULT; + kfree(data); + if (ret >= 0) { + free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ + } + return ret; +} + +static int update_config_rom(struct file_info *fi, struct pending_request *req) +{ + int ret=sizeof(struct raw1394_request); + quadlet_t *data = kmalloc(req->req.length, SLAB_KERNEL); + if (!data) return -ENOMEM; + if (copy_from_user(data,int2ptr(req->req.sendb), + req->req.length)) { + ret= -EFAULT; + } else { + int status = hpsb_update_config_rom(fi->host, + data, req->req.length, + (unsigned char) req->req.misc); + if (copy_to_user(int2ptr(req->req.recvb), + &status, sizeof(status))) + ret = -ENOMEM; + } + kfree(data); + if (ret >= 0) { + free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ + } + return ret; +} + +static int state_connected(struct file_info *fi, struct pending_request *req) +{ + int node = req->req.address >> 48; + + req->req.error = RAW1394_ERROR_NONE; + switch (req->req.type) { + + case RAW1394_REQ_ECHO: + queue_complete_req(req); + return sizeof(struct raw1394_request); + + case RAW1394_REQ_ISO_SEND: + return handle_iso_send(fi, req, node); + + case RAW1394_REQ_ARM_REGISTER: + return arm_register(fi, req); + + case RAW1394_REQ_ARM_UNREGISTER: + return arm_unregister(fi, req); + + case RAW1394_REQ_RESET_NOTIFY: + return reset_notification(fi, req); + case RAW1394_REQ_ISO_LISTEN: handle_iso_listen(fi, req); return sizeof(struct raw1394_request); @@ -831,21 +1908,49 @@ return sizeof(struct raw1394_request); case RAW1394_REQ_RESET_BUS: - hpsb_reset_bus(fi->host, LONG_RESET); + if (req->req.misc == RAW1394_LONG_RESET) { + DBGMSG("busreset called (type: LONG)"); + hpsb_reset_bus(fi->host, LONG_RESET); + free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ + return sizeof(struct raw1394_request); + } + if (req->req.misc == RAW1394_SHORT_RESET) { + DBGMSG("busreset called (type: SHORT)"); + hpsb_reset_bus(fi->host, SHORT_RESET); + free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */ + return sizeof(struct raw1394_request); + } + /* error EINVAL (22) invalid argument */ + return (-EINVAL); + case RAW1394_REQ_GET_ROM: + return get_config_rom(fi, req); + + case RAW1394_REQ_UPDATE_ROM: + return update_config_rom(fi, req); + } + + if (req->req.generation != get_hpsb_generation(fi->host)) { + req->req.error = RAW1394_ERROR_GENERATION; + req->req.generation = get_hpsb_generation(fi->host); + req->req.length = 0; + queue_complete_req(req); return sizeof(struct raw1394_request); } + switch (req->req.type) { + case RAW1394_REQ_PHYPACKET: + return write_phypacket(fi, req); + case RAW1394_REQ_ASYNC_SEND: + return handle_async_send(fi, req); + } + if (req->req.length == 0) { req->req.error = RAW1394_ERROR_INVALID_ARG; queue_complete_req(req); return sizeof(struct raw1394_request); } - if (fi->host->node_id == node) { - return handle_local_request(fi, req, node); - } - - return handle_remote_request(fi, req, node); + return handle_async_request(fi, req, node); } @@ -921,6 +2026,7 @@ return -ENOMEM; memset(fi, 0, sizeof(struct file_info)); + fi->notification = (u8) RAW1394_NOTIFY_ON; /* busreset notification */ INIT_LIST_HEAD(&fi->list); fi->state = opened; @@ -929,6 +2035,7 @@ sema_init(&fi->complete_sem, 0); spin_lock_init(&fi->reqlists_lock); init_waitqueue_head(&fi->poll_wait_complete); + INIT_LIST_HEAD(&fi->addr_list); file->private_data = fi; @@ -940,7 +2047,15 @@ struct file_info *fi = file->private_data; struct list_head *lh; struct pending_request *req; - int done = 0, i; + int done = 0, i, fail = 0; + int retval = 0; + struct list_head *entry; + struct arm_addr *addr = NULL; + struct list_head *lh_1, *lh_2; + struct host_info *hi; + struct file_info *fi_hlp = NULL; + struct arm_addr *arm_addr = NULL; + int another_host; for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { @@ -948,9 +2063,63 @@ } } - spin_lock(&host_info_lock); + spin_lock_irq(&host_info_lock); fi->listen_channels = 0; - spin_unlock(&host_info_lock); + spin_unlock_irq(&host_info_lock); + + fail = 0; + /* set address-entries invalid */ + spin_lock_irq(&host_info_lock); + + while (!list_empty(&fi->addr_list)) { + another_host = 0; + lh = fi->addr_list.next; + addr = list_entry(lh, struct arm_addr, addr_list); + /* another host with valid address-entry containing + same addressrange? */ + list_for_each(lh_1, &host_info_list) { + hi = list_entry(lh_1, struct host_info, list); + if (hi->host != fi->host) { + list_for_each(lh_2, &hi->file_info_list) { + fi_hlp = list_entry(lh_2, struct file_info, list); + entry = fi_hlp->addr_list.next; + while (entry != &(fi_hlp->addr_list)) { + arm_addr = list_entry(entry, + struct arm_addr, addr_list); + if (arm_addr->start == + addr->start) { + DBGMSG("raw1394_release: " + "another host ownes " + "same addressrange"); + another_host = 1; + break; + } + entry = entry->next; + } + if (another_host) { + break; + } + } + } + } + if (!another_host) { + DBGMSG("raw1394_release: call hpsb_arm_unregister"); + retval = hpsb_unregister_addrspace(hl_handle, addr->start); + if (!retval) { + ++fail; + printk(KERN_ERR "raw1394_release arm_Unregister failed\n"); + } + } + DBGMSG("raw1394_release: delete addr_entry from list"); + list_del(&addr->addr_list); + kfree(addr->addr_space_buffer); + kfree(addr); + } /* while */ + spin_unlock_irq(&host_info_lock); + if (fail > 0) { + printk(KERN_ERR "raw1394: during addr_list-release " + "error(s) occured \n"); + } while (!done) { spin_lock_irq(&fi->reqlists_lock); @@ -1009,28 +2178,28 @@ return -ENOMEM; } - devfs_handle = devfs_register(NULL, - RAW1394_DEVICE_NAME, DEVFS_FL_NONE, + devfs_handle = devfs_register(NULL, + RAW1394_DEVICE_NAME, DEVFS_FL_NONE, IEEE1394_MAJOR, - IEEE1394_MINOR_BLOCK_RAW1394 * 16, + IEEE1394_MINOR_BLOCK_RAW1394 * 16, S_IFCHR | S_IRUSR | S_IWUSR, &file_ops, NULL); if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394, - THIS_MODULE, &file_ops)) { + THIS_MODULE, &file_ops)) { HPSB_ERR("raw1394 failed to register minor device block"); - devfs_unregister(devfs_handle); - hpsb_unregister_highlevel(hl_handle); + devfs_unregister(devfs_handle); + hpsb_unregister_highlevel(hl_handle); return -EBUSY; } - printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME); + printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME); return 0; } static void __exit cleanup_raw1394(void) { ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394); - devfs_unregister(devfs_handle); + devfs_unregister(devfs_handle); hpsb_unregister_highlevel(hl_handle); } diff -Nru a/drivers/ieee1394/raw1394.h b/drivers/ieee1394/raw1394.h --- a/drivers/ieee1394/raw1394.h Tue Oct 15 20:29:11 2002 +++ b/drivers/ieee1394/raw1394.h Tue Oct 15 20:29:11 2002 @@ -14,20 +14,32 @@ #define RAW1394_REQ_SET_CARD 3 /* state: connected */ -#define RAW1394_REQ_ASYNC_READ 100 -#define RAW1394_REQ_ASYNC_WRITE 101 -#define RAW1394_REQ_LOCK 102 -#define RAW1394_REQ_LOCK64 103 -#define RAW1394_REQ_ISO_SEND 104 - -#define RAW1394_REQ_ISO_LISTEN 200 -#define RAW1394_REQ_FCP_LISTEN 201 -#define RAW1394_REQ_RESET_BUS 202 +#define RAW1394_REQ_ASYNC_READ 100 +#define RAW1394_REQ_ASYNC_WRITE 101 +#define RAW1394_REQ_LOCK 102 +#define RAW1394_REQ_LOCK64 103 +#define RAW1394_REQ_ISO_SEND 104 +#define RAW1394_REQ_ASYNC_SEND 105 + +#define RAW1394_REQ_ISO_LISTEN 200 +#define RAW1394_REQ_FCP_LISTEN 201 +#define RAW1394_REQ_RESET_BUS 202 +#define RAW1394_REQ_GET_ROM 203 +#define RAW1394_REQ_UPDATE_ROM 204 +#define RAW1394_REQ_ECHO 205 + +#define RAW1394_REQ_ARM_REGISTER 300 +#define RAW1394_REQ_ARM_UNREGISTER 301 + +#define RAW1394_REQ_RESET_NOTIFY 400 + +#define RAW1394_REQ_PHYPACKET 500 /* kernel to user */ #define RAW1394_REQ_BUS_RESET 10000 #define RAW1394_REQ_ISO_RECEIVE 10001 #define RAW1394_REQ_FCP_REQUEST 10002 +#define RAW1394_REQ_ARM 10003 /* error codes */ #define RAW1394_ERROR_NONE 0 @@ -45,6 +57,17 @@ #define RAW1394_ERROR_ABORTED (-1101) #define RAW1394_ERROR_TIMEOUT (-1102) +/* arm_codes */ +#define ARM_READ 1 +#define ARM_WRITE 2 +#define ARM_LOCK 4 + +#define RAW1394_LONG_RESET 0 +#define RAW1394_SHORT_RESET 1 + +/* busresetnotify ... */ +#define RAW1394_NOTIFY_OFF 0 +#define RAW1394_NOTIFY_ON 1 #include @@ -69,6 +92,29 @@ __u8 name[32]; }; +typedef struct arm_request { + nodeid_t destination_nodeid; + nodeid_t source_nodeid; + nodeaddr_t destination_offset; + u8 tlabel; + u8 tcode; + u_int8_t extended_transaction_code; + u_int32_t generation; + arm_length_t buffer_length; + byte_t *buffer; +} *arm_request_t; + +typedef struct arm_response { + int response_code; + arm_length_t buffer_length; + byte_t *buffer; +} *arm_response_t; + +typedef struct arm_request_response { + struct arm_request *request; + struct arm_response *response; +} *arm_request_response_t; + #ifdef __KERNEL__ struct iso_block_store { @@ -91,18 +137,34 @@ spinlock_t reqlists_lock; wait_queue_head_t poll_wait_complete; + struct list_head addr_list; + u8 *fcp_buffer; u64 listen_channels; quadlet_t *iso_buffer; size_t iso_buffer_length; + + u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */ +}; + +struct arm_addr { + struct list_head addr_list; /* file_info list */ + u64 start, end; + u64 arm_tag; + u8 access_rights; + u8 notification_options; + u8 client_transactions; + u64 recvb; + u16 rec_length; + u8 *addr_space_buffer; /* accessed by read/write/lock */ }; struct pending_request { struct list_head list; struct file_info *file_info; struct hpsb_packet *packet; - struct tq_struct tq; + struct hpsb_queue_struct tq; struct iso_block_store *ibs; quadlet_t *data; int free_data; diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c --- a/drivers/ieee1394/sbp2.c Tue Oct 15 20:29:12 2002 +++ b/drivers/ieee1394/sbp2.c Tue Oct 15 20:29:12 2002 @@ -351,7 +351,7 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Rev: 584 $ James Goodwin "; + "$Rev: 601 $ James Goodwin "; /* * Module load parameter definitions @@ -421,8 +421,9 @@ * talking to a single sbp2 device at the same time (filesystem coherency, * etc.). If you're running an sbp2 device that supports multiple logins, * and you're either running read-only filesystems or some sort of special - * filesystem supporting multiple hosts, then set sbp2_exclusive_login to - * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four + * filesystem supporting multiple hosts (one such filesystem is OpenGFS, + * see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login + * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four * concurrent logins. */ MODULE_PARM(sbp2_exclusive_login,"i"); @@ -800,8 +801,9 @@ * Set up a task queue completion routine, which returns * the packet to the free list and releases the tlabel. */ - request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet; - request_packet->tq.data = request_packet; + HPSB_PREPARE_WORK(&request_packet->tq, + (void (*)(void*))sbp2util_free_request_packet, + request_packet); request_packet->hi_context = hi; hpsb_add_packet_complete_task(packet, &request_packet->tq); @@ -1007,13 +1009,8 @@ command->dma_size, command->dma_dir); SBP2_DMA_FREE("single bulk"); } else if (command->dma_type == CMD_DMA_PAGE) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) - pci_unmap_single(hi->host->pdev, command->cmd_dma, - command->dma_size, command->dma_dir); -#else pci_unmap_page(hi->host->pdev, command->cmd_dma, command->dma_size, command->dma_dir); -#endif /* Linux version < 2.4.13 */ SBP2_DMA_FREE("single page"); } /* XXX: Check for CMD_DMA_NONE bug */ command->dma_type = CMD_DMA_NONE; @@ -2146,17 +2143,11 @@ command->dma_dir = dma_dir; command->dma_size = sgpnt[0].length; command->dma_type = CMD_DMA_PAGE; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13) - command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address, - command->dma_size, - command->dma_dir); -#else command->cmd_dma = pci_map_page(hi->host->pdev, sgpnt[0].page, sgpnt[0].offset, command->dma_size, command->dma_dir); -#endif /* Linux version < 2.4.13 */ SBP2_DMA_ALLOC("single page scatter element"); command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id); @@ -2702,7 +2693,7 @@ * This function deals with status writes from the SBP-2 device */ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, unsigned int length) + quadlet_t *data, u64 addr, unsigned int length, u16 fl) { struct sbp2scsi_host_info *hi = NULL; struct scsi_id_instance_data *scsi_id = NULL; @@ -3161,7 +3152,6 @@ heads = 64; sectors = 32; cylinders = (int)disk->capacity / (heads * sectors); - if (cylinders > 1024) { heads = 255; diff -Nru a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h --- a/drivers/ieee1394/sbp2.h Tue Oct 15 20:29:12 2002 +++ b/drivers/ieee1394/sbp2.h Tue Oct 15 20:29:12 2002 @@ -324,7 +324,7 @@ struct list_head list; struct hpsb_packet *packet; - struct tq_struct tq; + struct hpsb_queue_struct tq; void *hi_context; }; @@ -510,9 +510,9 @@ #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data, - u64 addr, unsigned int length); + u64 addr, unsigned int length, u16 flags); static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data, - u64 addr, unsigned int length); + u64 addr, unsigned int length, u16 flags); #endif /* @@ -522,7 +522,7 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid, - quadlet_t *data, u64 addr, unsigned int length); + quadlet_t *data, u64 addr, unsigned int length, u16 flags); static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 flags); static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c --- a/drivers/ieee1394/video1394.c Tue Oct 15 20:29:12 2002 +++ b/drivers/ieee1394/video1394.c Tue Oct 15 20:29:12 2002 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -1455,12 +1454,7 @@ return -EIO; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, - strlen(VIDEO1394_DRIVER_NAME), NULL); -#else devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL); -#endif hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops); if (hl_handle == NULL) { diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c --- a/drivers/isdn/hardware/eicon/divasmain.c Tue Oct 15 20:29:12 2002 +++ b/drivers/isdn/hardware/eicon/divasmain.c Tue Oct 15 20:29:12 2002 @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -73,7 +73,7 @@ typedef struct _diva_os_thread_dpc { struct tasklet_struct divas_task; diva_os_soft_isr_t* psoft_isr; - struct tq_struct trap_script_task; + struct work_struct trap_script_task; int card_failed; } diva_os_thread_dpc_t; @@ -297,7 +297,7 @@ if (context && !context->card_failed) { context->card_failed = ANum+1; - schedule_task(&context->trap_script_task); + schedule_work(&context->trap_script_task); } } @@ -607,7 +607,7 @@ psoft_isr->callback = callback; psoft_isr->callback_context = callback_context; pdpc->psoft_isr = psoft_isr; - INIT_TQUEUE(&pdpc->trap_script_task, diva_adapter_trapped, pdpc); + INIT_WORK(&pdpc->trap_script_task, diva_adapter_trapped, pdpc); tasklet_init(&pdpc->divas_task, diva_os_dpc_proc, (unsigned long)pdpc); return (0); @@ -643,7 +643,7 @@ mem = psoft_isr->object; psoft_isr->object = 0; - flush_scheduled_tasks(); + flush_scheduled_work(); diva_os_free (0, mem); } } diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Tue Oct 15 20:29:15 2002 +++ b/drivers/md/md.c Tue Oct 15 20:29:15 2002 @@ -1394,12 +1394,11 @@ #endif } - disk = alloc_disk(); + disk = alloc_disk(1); if (!disk) return -ENOMEM; disk->major = MD_MAJOR; disk->first_minor = mdidx(mddev); - disk->minor_shift = 0; sprintf(disk->disk_name, "md%d", mdidx(mddev)); disk->fops = &md_fops; @@ -2732,18 +2731,9 @@ return 0; } -static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK]; void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors) { - kdev_t dev = to_kdev_t(rdev->bdev->bd_dev); - unsigned int major = major(dev); - unsigned int index; - - index = disk_index(dev); - if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - return; - - sync_io[major][index] += nr_sectors; + rdev->bdev->bd_disk->sync_io += nr_sectors; } static int is_mddev_idle(mddev_t *mddev) @@ -2755,16 +2745,8 @@ idle = 1; ITERATE_RDEV(mddev,rdev,tmp) { - kdev_t dev = to_kdev_t(rdev->bdev->bd_dev); - int major = major(dev); - int idx = disk_index(dev); - - if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - continue; - - curr_events = kstat.dk_drive_rblk[major][idx] + - kstat.dk_drive_wblk[major][idx] ; - curr_events -= sync_io[major][idx]; + struct gendisk *disk = rdev->bdev->bd_disk; + curr_events = disk->reads + disk->writes - disk->sync_io; if ((curr_events - rdev->last_events) > 32) { rdev->last_events = curr_events; idle = 0; diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c --- a/drivers/md/raid0.c Tue Oct 15 20:29:17 2002 +++ b/drivers/md/raid0.c Tue Oct 15 20:29:17 2002 @@ -162,6 +162,29 @@ return 1; } +/** + * raid0_mergeable_bvec -- tell bio layer if a two requests can be merged + * @q: request queue + * @bio: the buffer head that's been built up so far + * @biovec: the request that could be merged to it. + * + * Return 1 if the merge is not permitted (because the + * result would cross a chunk boundary), 0 otherwise. + */ +static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec) +{ + mddev_t *mddev = q->queuedata; + sector_t block; + unsigned int chunk_size; + unsigned int bio_sz; + + chunk_size = mddev->chunk_size >> 10; + block = bio->bi_sector >> 1; + bio_sz = (bio->bi_size + biovec->bv_len) >> 10; + + return chunk_size < ((block & (chunk_size - 1)) + bio_sz); +} + static int raid0_run (mddev_t *mddev) { unsigned cur=0, i=0, nb_zone; @@ -233,6 +256,8 @@ conf->hash_table[i++].zone1 = conf->strip_zone + cur; size -= (conf->smallest->size - zone0_size); } + blk_queue_max_sectors(&mddev->queue, mddev->chunk_size >> 9); + blk_queue_merge_bvec(&mddev->queue, raid0_mergeable_bvec); return 0; out_free_zone_conf: @@ -262,13 +287,6 @@ return 0; } -/* - * FIXME - We assume some things here : - * - requested buffers NEVER bigger than chunk size, - * - requested buffers NEVER cross stripes limits. - * Of course, those facts may not be valid anymore (and surely won't...) - * Hey guys, there's some work out there ;-) - */ static int raid0_make_request (request_queue_t *q, struct bio *bio) { mddev_t *mddev = q->queuedata; @@ -286,13 +304,16 @@ { +#if __GNUC__ < 3 + volatile +#endif sector_t x = block; sector_div(x, (unsigned long)conf->smallest->size); hash = conf->hash_table + x; } - /* Sanity check */ - if (chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10)) + /* Sanity check -- queue functions should prevent this happening */ + if (unlikely(chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10))) goto bad_map; if (!hash) diff -Nru a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c --- a/drivers/media/video/bttv-driver.c Tue Oct 15 20:29:20 2002 +++ b/drivers/media/video/bttv-driver.c Tue Oct 15 20:29:20 2002 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include diff -Nru a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c --- a/drivers/media/video/bttv-risc.c Tue Oct 15 20:29:17 2002 +++ b/drivers/media/video/bttv-risc.c Tue Oct 15 20:29:17 2002 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h --- a/drivers/media/video/bttvp.h Tue Oct 15 20:29:16 2002 +++ b/drivers/media/video/bttvp.h Tue Oct 15 20:29:16 2002 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include diff -Nru a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c --- a/drivers/media/video/cpia.c Tue Oct 15 20:29:19 2002 +++ b/drivers/media/video/cpia.c Tue Oct 15 20:29:19 2002 @@ -56,7 +56,7 @@ #ifdef MODULE MODULE_PARM(video_nr,"i"); -MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); +MODULE_AUTHOR("Scott J. Bertin & Peter Pregler & Johannes Erdfelt "); MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("video"); @@ -163,7 +163,7 @@ #define COMMAND_SETAPCOR 0x1000 #define COMMAND_SETFLICKERCTRL 0x2000 #define COMMAND_SETVLOFFSET 0x4000 - +#define COMMAND_SETLIGHTS 0x8000 /* Developer's Guide Table 5 p 3-34 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ static u8 flicker_jumps[2][2][4] = @@ -244,7 +244,7 @@ char *out = page; int len, tmp; struct cam_data *cam = data; - char tmpstr[20]; + char tmpstr[29]; /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ @@ -281,6 +281,13 @@ cam->params.status.vpStatus); out += sprintf(out, "error_code: %#04x\n", cam->params.status.errorCode); + /* QX3 specific entries */ + if (cam->params.qx3.qx3_detected) { + out += sprintf(out, "button: %4d\n", + cam->params.qx3.button); + out += sprintf(out, "cradled: %4d\n", + cam->params.qx3.cradled); + } out += sprintf(out, "video_size: %s\n", cam->params.format.videoSize == VIDEOSIZE_CIF ? "CIF " : "QCIF"); @@ -345,16 +352,17 @@ if (cam->params.version.firmwareVersion == 1 && cam->params.version.firmwareRevision == 2) /* 1-02 firmware limits gain to 2 */ - sprintf(tmpstr, "%8d %8d", 1, 2); + sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2); else - sprintf(tmpstr, "1,2,4,8"); + sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2); if (cam->params.exposure.gainMode == 0) - out += sprintf(out, "max_gain: unknown %18s" - " %8d\n", tmpstr, 2); + out += sprintf(out, "max_gain: unknown %28s" + " powers of 2\n", tmpstr); else - out += sprintf(out, "max_gain: %8d %18s %8d\n", - 1<<(cam->params.exposure.gainMode-1), tmpstr, 2); + out += sprintf(out, "max_gain: %8d %28s" + " 1,2,4 or 8 \n", + 1<<(cam->params.exposure.gainMode-1), tmpstr); switch(cam->params.exposure.expMode) { case 1: @@ -481,6 +489,15 @@ out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n", cam->params.compressionParams.decimationThreshMod, 0, 255, 2); + /* QX3 specific entries */ + if (cam->params.qx3.qx3_detected) { + out += sprintf(out, "toplight: %8s %8s %8s %8s\n", + cam->params.qx3.toplight ? "on" : "off", + "off", "on", "off"); + out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n", + cam->params.qx3.bottomlight ? "on" : "off", + "off", "on", "off"); + } len = out - page; len -= off; @@ -494,18 +511,45 @@ return len; } -static int cpia_write_proc(struct file *file, const char *buffer, +static int cpia_write_proc(struct file *file, const char *buf, unsigned long count, void *data) { - return -EINVAL; -#if 0 struct cam_data *cam = data; struct cam_params new_params; + char *page, *buffer; int retval, find_colon; int size = count; - unsigned long val; + unsigned long val = 0; u32 command_flags = 0; u8 new_mains; + + /* + * This code to copy from buf to page is shamelessly copied + * from the comx driver + */ + if (count > PAGE_SIZE) { + printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE); + return -ENOSPC; + } + + if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; + + if(copy_from_user(page, buf, count)) + { + retval = -EFAULT; + goto out; + } + + if (page[count-1] == '\n') + page[count-1] = '\0'; + else if (count < PAGE_SIZE) + page[count] = '\0'; + else if (page[count]) { + retval = -EINVAL; + goto out; + } + + buffer = page; if (down_interruptible(&cam->param_lock)) return -ERESTARTSYS; @@ -1163,6 +1207,22 @@ retval = -EINVAL; } command_flags |= COMMAND_SETCOMPRESSIONPARAMS; + } else if (MATCH("toplight")) { + if (!retval && MATCH("on")) + new_params.qx3.toplight = 1; + else if (!retval && MATCH("off")) + new_params.qx3.toplight = 0; + else + retval = -EINVAL; + command_flags |= COMMAND_SETLIGHTS; + } else if (MATCH("bottomlight")) { + if (!retval && MATCH("on")) + new_params.qx3.bottomlight = 1; + else if (!retval && MATCH("off")) + new_params.qx3.bottomlight = 0; + else + retval = -EINVAL; + command_flags |= COMMAND_SETLIGHTS; } else { DBG("No match found\n"); retval = -EINVAL; @@ -1174,7 +1234,10 @@ ++buffer; } if (count) { - if (*buffer != '\n' && *buffer != ';') + if (*buffer == '\0' && count != 1) + retval = -EINVAL; + else if (*buffer != '\n' && *buffer != ';' && + *buffer != '\0') retval = -EINVAL; else { --count; @@ -1208,8 +1271,9 @@ up(&cam->param_lock); - return retval; -#endif +out: + free_page((unsigned long)page); + return retval; } static void create_proc_cpia_cam(struct cam_data *cam) @@ -1229,7 +1293,12 @@ ent->data = cam; ent->read_proc = cpia_read_proc; ent->write_proc = cpia_write_proc; - ent->size = 3626; + /* + size of the proc entry is 3672 bytes for the standard webcam; + the extra features of the QX3 microscope add 188 bytes. + (we have not yet probed the camera to see which type it is). + */ + ent->size = 3672 + 188; cam->proc_entry = ent; } @@ -1523,6 +1592,10 @@ down(&cam->param_lock); datasize=8; break; + case CPIA_COMMAND_ReadMCPorts: + case CPIA_COMMAND_ReadVCRegs: + datasize = 4; + break; default: datasize=0; break; @@ -1620,6 +1693,22 @@ } up(&cam->param_lock); break; + + case CPIA_COMMAND_ReadMCPorts: + if (!cam->params.qx3.qx3_detected) + break; + /* test button press */ + cam->params.qx3.button = ((data[1] & 0x02) == 0); + if (cam->params.qx3.button) { + /* button pressed - unlock the latch */ + do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0); + do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0); + } + + /* test whether microscope is cradled */ + cam->params.qx3.cradled = ((data[2] & 0x40) == 0); + break; + default: break; } @@ -1779,6 +1868,7 @@ { switch(fmt) { case VIDEO_PALETTE_GREY: + return count; case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_YUV422: @@ -2059,6 +2149,13 @@ if (cam->cmd_queue & COMMAND_RESUME) init_stream_cap(cam); + if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) { + int p1 = (cam->params.qx3.bottomlight == 0) << 1; + int p2 = (cam->params.qx3.toplight == 0) << 3; + do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0); + do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0); + } + up(&cam->param_lock); cam->cmd_queue = COMMAND_NONE; return; @@ -2133,9 +2230,10 @@ /* camera idle now so dispatch queued commands */ dispatch_commands(cam); - /* Update our knowledge of the camera state - FIXME: necessary? */ - do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); - do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + /* Update our knowledge of the camera state */ + do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); + do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); + do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); /* decompress and convert image to by copying it from * raw_image to decompressed_frame @@ -2346,8 +2444,12 @@ get_version_information(cam); if (cam->params.version.firmwareVersion != 1) return -ENODEV; - - /* The fatal error checking should be done after + + /* set QX3 detected flag */ + cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 && + cam->params.pnpID.product == 0x0001); + + /* The fatal error checking should be done after * the camera powers up (developer's guide p 3-38) */ /* Set streamState before transition to high power to avoid bug @@ -2481,7 +2583,7 @@ /* GotoLoPower */ goto_low_power(cam); - /* Update the camera ststus */ + /* Update the camera status */ do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); /* cleanup internal state stuff */ @@ -2520,7 +2622,7 @@ struct video_device *dev = file->private_data; struct cam_data *cam = dev->priv; - /* make this _really_ smp and multithredi-safe */ + /* make this _really_ smp and multithread-safe */ if (down_interruptible(&cam->busy_lock)) return -EINTR; @@ -2728,7 +2830,6 @@ cam->cmd_queue |= COMMAND_SETFORMAT; } - // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw)); up(&cam->param_lock); /* setformat ignored by camera during streaming, @@ -2762,10 +2863,8 @@ struct video_mmap *vm = arg; int video_size; -#if 1 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame, vm->width, vm->height); -#endif if (vm->frame<0||vm->frame>=FRAME_NUM) { retval = -EINVAL; break; @@ -2775,6 +2874,8 @@ cam->vp.palette = vm->format; switch(vm->format) { case VIDEO_PALETTE_GREY: + cam->vp.depth=8; + break; case VIDEO_PALETTE_RGB555: case VIDEO_PALETTE_RGB565: case VIDEO_PALETTE_YUV422: @@ -2807,10 +2908,6 @@ cam->cmd_queue |= COMMAND_SETFORMAT; dispatch_commands(cam); } -#if 0 - DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size, - cam->vw.width, cam->vw.height); -#endif /* according to v4l-spec we must start streaming here */ cam->mmap_kludge = 1; retval = capture_frame(cam, vm); @@ -2947,7 +3044,7 @@ owner: THIS_MODULE, name: "CPiA Camera", type: VID_TYPE_CAPTURE, - hardware: VID_HARDWARE_CPIA, /* FIXME */ + hardware: VID_HARDWARE_CPIA, fops: &cpia_fops, }; @@ -3006,8 +3103,8 @@ cam->params.sensorFps.divisor = 1; cam->params.sensorFps.baserate = 1; - cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */ - cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */ + cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */ + cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */ cam->params.format.subSample = SUBSAMPLE_422; cam->params.format.yuvOrder = YUVORDER_YUYV; @@ -3015,8 +3112,14 @@ cam->params.compression.mode = CPIA_COMPRESSION_AUTO; cam->params.compressionTarget.frTargeting = CPIA_COMPRESSION_TARGET_QUALITY; - cam->params.compressionTarget.targetFR = 7; /* FIXME? */ - cam->params.compressionTarget.targetQ = 10; /* FIXME? */ + cam->params.compressionTarget.targetFR = 15; /* From windows driver */ + cam->params.compressionTarget.targetQ = 5; /* From windows driver */ + + cam->params.qx3.qx3_detected = 0; + cam->params.qx3.toplight = 0; + cam->params.qx3.bottomlight = 0; + cam->params.qx3.button = 0; + cam->params.qx3.cradled = 0; cam->video_size = VIDEOSIZE_CIF; @@ -3025,8 +3128,8 @@ cam->vp.brightness = 32768; /* 50% */ cam->vp.contrast = 32768; /* 50% */ cam->vp.whiteness = 0; /* not used -> grayscale only */ - cam->vp.depth = 0; /* FIXME: to be set by user? */ - cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */ + cam->vp.depth = 24; /* to be set by user */ + cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */ cam->vw.x = 0; cam->vw.y = 0; @@ -3080,14 +3183,9 @@ { struct cam_data *camera; - /* Need a lock when adding/removing cameras. This doesn't happen - * often and doesn't take very long, so grabbing the kernel lock - * should be OK. */ - - if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) { - unlock_kernel(); + if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) return NULL; - } + init_camera_struct( camera, ops ); camera->lowlevel_data = lowlevel; @@ -3095,7 +3193,6 @@ /* register v4l device */ if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { kfree(camera); - unlock_kernel(); printk(KERN_DEBUG "video_register_device failed\n"); return NULL; } @@ -3118,12 +3215,6 @@ /* close cpia */ camera->ops->close(camera->lowlevel_data); -/* Eh? Feeling happy? - jerdfelt */ -/* - camera->ops->open(camera->lowlevel_data); - camera->ops->close(camera->lowlevel_data); -*/ - printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n", camera->params.version.firmwareVersion, camera->params.version.firmwareRevision, diff -Nru a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h --- a/drivers/media/video/cpia.h Tue Oct 15 20:29:21 2002 +++ b/drivers/media/video/cpia.h Tue Oct 15 20:29:21 2002 @@ -27,12 +27,12 @@ */ #define CPIA_MAJ_VER 0 -#define CPIA_MIN_VER 7 -#define CPIA_PATCH_VER 4 +#define CPIA_MIN_VER 8 +#define CPIA_PATCH_VER 1 #define CPIA_PP_MAJ_VER 0 -#define CPIA_PP_MIN_VER 7 -#define CPIA_PP_PATCH_VER 4 +#define CPIA_PP_MIN_VER 8 +#define CPIA_PP_PATCH_VER 1 #define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */ #define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */ @@ -203,7 +203,14 @@ u8 videoSize; /* CIF/QCIF */ u8 subSample; u8 yuvOrder; - } format; + } format; + struct { /* Intel QX3 specific data */ + u8 qx3_detected; /* a QX3 is present */ + u8 toplight; /* top light lit , R/W */ + u8 bottomlight; /* bottom light lit, R/W */ + u8 button; /* snapshot button pressed (R/O) */ + u8 cradled; /* microscope is in cradle (R/O) */ + } qx3; struct { u8 colStart; /* skip first 8*colStart pixels */ u8 colEnd; /* finish at 8*colEnd pixels */ @@ -393,29 +400,6 @@ (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\ (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0); -#define ADD_TO_LIST(l, drv) \ - {\ - lock_kernel();\ - (drv)->next = l;\ - (drv)->previous = &(l);\ - (l) = drv;\ - unlock_kernel();\ - } while(0) - -#define REMOVE_FROM_LIST(drv) \ - {\ - if ((drv)->previous != NULL) {\ - lock_kernel();\ - if ((drv)->next != NULL)\ - (drv)->next->previous = (drv)->previous;\ - *((drv)->previous) = (drv)->next;\ - (drv)->previous = NULL;\ - (drv)->next = NULL;\ - unlock_kernel();\ - }\ - } while (0) - - static inline void cpia_add_to_list(struct cam_data* l, struct cam_data* drv) { drv->next = l; @@ -423,7 +407,6 @@ l = drv; } - static inline void cpia_remove_from_list(struct cam_data* drv) { if (drv->previous != NULL) { @@ -434,7 +417,6 @@ drv->next = NULL; } } - #endif /* __KERNEL__ */ diff -Nru a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c --- a/drivers/media/video/cpia_pp.c Tue Oct 15 20:29:11 2002 +++ b/drivers/media/video/cpia_pp.c Tue Oct 15 20:29:11 2002 @@ -4,7 +4,7 @@ * Supports CPiA based parallel port Video Camera's. * * (C) Copyright 1999 Bas Huisman - * (C) Copyright 1999-2000 Scott J. Bertin , + * (C) Copyright 1999-2000 Scott J. Bertin , * (C) Copyright 1999-2000 Peter Pregler * * This program is free software; you can redistribute it and/or modify @@ -341,17 +341,6 @@ return 0; } -static int cpia_pp_read(struct parport *port, u8 *buffer, int len) -{ - int bytes_read, new_bytes; - for(bytes_read=0; bytes_readimage_complete ) { - cond_resched(); - - new_bytes = cpia_pp_read(cam->port, buffer, block_size ); - if( new_bytes <= 0 ) { - break; - } - i=-1; - while(++iimage_complete=1; - break; - } - if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) { - block_size=CPIA_MAX_IMAGE_SIZE-read_bytes; - } - } + read_bytes = parport_read(cam->port, buffer, CPIA_MAX_IMAGE_SIZE ); + EndTransferMode(cam); + DBG("read %d bytes\n", read_bytes); + if( read_bytes<0) return -EIO; + endseen = 0; + for( i=0; i3 ) { + cam->image_complete=1; + DBG("endseen at %d bytes\n", i); + } return cam->image_complete ? read_bytes : -EIO; } @@ -716,15 +695,6 @@ static int __init cpia_pp_setup(char *str) { -#if 0 - /* Is this only a 2.2ism? -jerdfelt */ - if (!str) { - if (ints[0] == 0 || ints[1] == 0) { - /* disable driver on "cpia_pp=" or "cpia_pp=0" */ - parport_nr[0] = PPCPIA_PARPORT_OFF; - } - } else -#endif if (!strncmp(str, "parport", 7)) { int n = simple_strtoul(str + 7, NULL, 10); if (parport_ptr < PARPORT_MAX) { diff -Nru a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c --- a/drivers/media/video/cpia_usb.c Tue Oct 15 20:29:11 2002 +++ b/drivers/media/video/cpia_usb.c Tue Oct 15 20:29:11 2002 @@ -273,14 +273,16 @@ error_urb1: /* free urb 1 */ usb_free_urb(ucpia->sbuf[1].urb); - + ucpia->sbuf[1].urb = NULL; error_urb0: /* free urb 0 */ usb_free_urb(ucpia->sbuf[0].urb); - + ucpia->sbuf[0].urb = NULL; error_1: kfree (ucpia->sbuf[1].data); + ucpia->sbuf[1].data = NULL; error_0: kfree (ucpia->sbuf[0].data); + ucpia->sbuf[0].data = NULL; return retval; } @@ -636,8 +638,10 @@ ucpia->buffers[0] = NULL; } - if (!ucpia->open) - kfree(ucpia); + if (!ucpia->open) { + kfree(ucpia); + cam->lowlevel_data = NULL; + } } static int __init usb_cpia_init(void) diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c --- a/drivers/media/video/video-buf.c Tue Oct 15 20:29:17 2002 +++ b/drivers/media/video/video-buf.c Tue Oct 15 20:29:17 2002 @@ -18,8 +18,8 @@ #include #include -#include #include +#include #include #include #include @@ -65,32 +65,31 @@ return NULL; } -struct scatterlist* -videobuf_iobuf_to_sg(struct kiobuf *iobuf) +struct scatterlist * +videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset) { struct scatterlist *sglist; int i = 0; - - sglist = kmalloc(sizeof(struct scatterlist) * iobuf->nr_pages, - GFP_KERNEL); + + if (NULL == pages[0]) + return NULL; + sglist = kmalloc(sizeof(*sglist) * nr_pages, GFP_KERNEL); if (NULL == sglist) return NULL; - memset(sglist,0,sizeof(struct scatterlist) * iobuf->nr_pages); + memset(sglist, 0, sizeof(*sglist) * nr_pages); - if (NULL == iobuf->maplist[0]) - goto err; - if (PageHighMem(iobuf->maplist[0])) + if (PageHighMem(pages[0])) /* DMA to highmem pages might not work */ goto err; - sglist[0].page = iobuf->maplist[0]; - sglist[0].offset = iobuf->offset; - sglist[0].length = PAGE_SIZE - iobuf->offset; - for (i = 1; i < iobuf->nr_pages; i++) { - if (NULL == iobuf->maplist[i]) + sglist[0].page = pages[0]; + sglist[0].offset = offset; + sglist[0].length = PAGE_SIZE - offset; + for (i = 1; i < nr_pages; i++) { + if (NULL == pages[i]) goto err; - if (PageHighMem(iobuf->maplist[i])) + if (PageHighMem(pages[i])) goto err; - sglist[i].page = iobuf->maplist[i]; + sglist[i].page = pages[i]; sglist[i].length = PAGE_SIZE; } return sglist; @@ -100,6 +99,30 @@ return NULL; } +int videobuf_lock(struct page **pages, int nr_pages) +{ + int i; + + for (i = 0; i < nr_pages; i++) + if (TestSetPageLocked(pages[i])) + goto err; + return 0; + + err: + while (i > 0) + unlock_page(pages[--i]); + return -EINVAL; +} + +int videobuf_unlock(struct page **pages, int nr_pages) +{ + int i; + + for (i = 0; i < nr_pages; i++) + unlock_page(pages[i]); + return 0; +} + /* --------------------------------------------------------------------- */ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction, @@ -113,14 +136,21 @@ case PCI_DMA_TODEVICE: rw = WRITE; break; default: BUG(); } - if (0 != (err = alloc_kiovec(1,&dma->iobuf))) - return err; - if (0 != (err = map_user_kiobuf(rw, dma->iobuf, data, size))) { - dprintk(1,"map_user_kiobuf: %d\n",err); - return err; - } - dma->nr_pages = dma->iobuf->nr_pages; - return 0; + + dma->offset = data & PAGE_MASK; + dma->nr_pages = ((((data+size) & ~PAGE_MASK) - + (data & ~PAGE_MASK)) >> PAGE_SHIFT) +1; + dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*), + GFP_KERNEL); + if (NULL == dma->pages) + return -ENOMEM; + down_read(¤t->mm->mmap_sem); + err = get_user_pages(current,current->mm, + data, dma->nr_pages, + rw == READ, 0, /* don't force */ + dma->pages, NULL); + up_read(¤t->mm->mmap_sem); + return err; } int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction, @@ -144,13 +174,15 @@ if (0 == dma->nr_pages) BUG(); - if (dma->iobuf) { - if (0 != (err = lock_kiovec(1,&dma->iobuf,1))) { - dprintk(1,"lock_kiovec: %d\n",err); + if (dma->pages) { + if (0 != (err = videobuf_lock(dma->pages, dma->nr_pages))) { + dprintk(1,"videobuf_lock_pages: %d\n",err); return err; } - dma->sglist = videobuf_iobuf_to_sg(dma->iobuf); + dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages, + dma->offset); } + if (dma->vmalloc) { dma->sglist = videobuf_vmalloc_to_sg (dma->vmalloc,dma->nr_pages); @@ -160,7 +192,7 @@ return -ENOMEM; } dma->sglen = pci_map_sg(dev,dma->sglist,dma->nr_pages, - dma->direction); + dma->direction); return 0; } @@ -182,8 +214,8 @@ kfree(dma->sglist); dma->sglist = NULL; dma->sglen = 0; - if (dma->iobuf) - unlock_kiovec(1,&dma->iobuf); + if (dma->pages) + videobuf_lock(dma->pages, dma->nr_pages); return 0; } @@ -192,11 +224,14 @@ if (dma->sglen) BUG(); - if (dma->iobuf) { - unmap_kiobuf(dma->iobuf); - free_kiovec(1,&dma->iobuf); - dma->iobuf = NULL; + if (dma->pages) { + int i; + for (i=0; i < dma->nr_pages; i++) + page_cache_release(dma->pages[i]); + kfree(dma->pages); + dma->pages = NULL; } + if (dma->vmalloc) { vfree(dma->vmalloc); dma->vmalloc = NULL; @@ -959,6 +994,7 @@ map->q = q; vma->vm_ops = &videobuf_vm_ops; vma->vm_flags |= VM_DONTEXPAND; + vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */ vma->vm_private_data = map; dprintk(1,"mmap %p: %08lx-%08lx pgoff %08lx bufs %d-%d\n", map,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last); @@ -972,7 +1008,6 @@ /* --------------------------------------------------------------------- */ EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg); -EXPORT_SYMBOL_GPL(videobuf_iobuf_to_sg); EXPORT_SYMBOL_GPL(videobuf_dma_init_user); EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel); diff -Nru a/drivers/media/video/video-buf.h b/drivers/media/video/video-buf.h --- a/drivers/media/video/video-buf.h Tue Oct 15 20:29:17 2002 +++ b/drivers/media/video/video-buf.h Tue Oct 15 20:29:17 2002 @@ -28,11 +28,12 @@ struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages); /* - * Return a scatterlist for a locked iobuf (NULL on errors). Memory + * Return a scatterlist for a an array of userpages (NULL on errors). Memory * for the scatterlist is allocated using kmalloc. The caller must * free the memory. */ -struct scatterlist* videobuf_iobuf_to_sg(struct kiobuf *iobuf); +struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages, + int offset); /* --------------------------------------------------------------------- */ @@ -57,7 +58,8 @@ struct videobuf_dmabuf { /* for userland buffer */ - struct kiobuf *iobuf; + struct page **pages; + int offset; /* for kernel buffers */ void *vmalloc; diff -Nru a/drivers/message/fusion/Config.help b/drivers/message/fusion/Config.help --- a/drivers/message/fusion/Config.help Tue Oct 15 20:29:16 2002 +++ b/drivers/message/fusion/Config.help Tue Oct 15 20:29:16 2002 @@ -42,6 +42,16 @@ architecture is based on LSI Logic's Message Passing Interface (MPI) specification. +Maximum number of scatter gather entries +CONFIG_FUSION_MAX_SGE + This option allows you to specify the maximum number of scatter- + gather entries per I/O. The driver defaults to 40, a reasonable number + for most systems. However, the user may increase this up to 128. + Increasing this parameter will require significantly more memory + on a per controller instance. Increasing the parameter is not + necessary (or recommended) unless the user will be running + large I/O's via the raw interface. + CONFIG_FUSION_ISENSE The isense module (roughly stands for Interpret SENSE data) is completely optional. It simply provides extra English readable diff -Nru a/drivers/message/fusion/Config.in b/drivers/message/fusion/Config.in --- a/drivers/message/fusion/Config.in Tue Oct 15 20:29:15 2002 +++ b/drivers/message/fusion/Config.in Tue Oct 15 20:29:15 2002 @@ -10,6 +10,7 @@ else define_bool CONFIG_FUSION_BOOT n fi + int " Maximum number of scatter gather entries" CONFIG_FUSION_MAX_SGE 40 if [ "$CONFIG_MODULES" = "y" ]; then # How can we force these options to module or nothing? diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h --- a/drivers/message/fusion/linux_compat.h Tue Oct 15 20:29:15 2002 +++ b/drivers/message/fusion/linux_compat.h Tue Oct 15 20:29:15 2002 @@ -253,24 +253,35 @@ #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) -#define mptscsih_save_flags(flags) \ -({ local_irq_save(flags); \ -}) +#define mptscsih_lock(iocp, flags) \ + spin_lock_irqsave(&iocp->FreeQlock, flags) #else -#define mptscsih_save_flags(flags) \ +#define mptscsih_lock(iocp, flags) \ ({ save_flags(flags); \ cli(); \ }) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) -#define mptscsih_restore_flags(flags) \ -({ local_irq_enable(); \ - local_irq_restore(flags); \ -}) +#define mptscsih_unlock(iocp, flags) \ + spin_unlock_irqrestore(&iocp->FreeQlock, flags) +#else +#define mptscsih_unlock(iocp, flags) restore_flags(flags); +#endif + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) +#define mpt_work_struct work_struct +#define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data) #else -#define mptscsih_restore_flags(flags) restore_flags(flags); +#define mpt_work_struct tq_struct +#define MPT_INIT_WORK(_task, _func, _data) \ +({ (_task)->sync = 0; \ + (_task)->routine = (_func); \ + (_task)->data = (void *) (_data); \ +}) #endif + /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* _LINUX_COMPAT_H */ diff -Nru a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h --- a/drivers/message/fusion/lsi/mpi.h Tue Oct 15 20:29:12 2002 +++ b/drivers/message/fusion/lsi/mpi.h Tue Oct 15 20:29:12 2002 @@ -6,7 +6,7 @@ * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * MPI.H Version: 01.02.06 + * MPI.H Version: 01.02.07 * * Version History * --------------- @@ -47,6 +47,7 @@ * 03-14-02 01.02.04 Added MPI_HEADER_VERSION_ defines. * 05-31-02 01.02.05 Bumped MPI_HEADER_VERSION_UNIT. * 07-12-02 01.02.06 Added define for MPI_FUNCTION_MAILBOX. + * 09-16-02 01.02.07 Bumped value for MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -75,7 +76,7 @@ /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x07) +#define MPI_HEADER_VERSION_UNIT (0x09) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) diff -Nru a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h --- a/drivers/message/fusion/lsi/mpi_cnfg.h Tue Oct 15 20:29:17 2002 +++ b/drivers/message/fusion/lsi/mpi_cnfg.h Tue Oct 15 20:29:17 2002 @@ -6,7 +6,7 @@ * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * MPI_CNFG.H Version: 01.02.08 + * MPI_CNFG.H Version: 01.02.09 * * Version History * --------------- @@ -127,6 +127,7 @@ * MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE. * Added new config page: CONFIG_PAGE_SCSI_DEVICE_3. * Modified MPI_FCPORTPAGE5_FLAGS_ defines. + * 09-16-02 01.02.09 Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define. * -------------------------------------------------------------------------- */ @@ -814,6 +815,7 @@ #define MPI_SCSIDEVPAGE1_CONF_WDTR_DISALLOWED (0x00000002) #define MPI_SCSIDEVPAGE1_CONF_SDTR_DISALLOWED (0x00000004) #define MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE (0x00000008) +#define MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG (0x00000010) typedef struct _CONFIG_PAGE_SCSI_DEVICE_2 diff -Nru a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h --- a/drivers/message/fusion/lsi/mpi_targ.h Tue Oct 15 20:29:12 2002 +++ b/drivers/message/fusion/lsi/mpi_targ.h Tue Oct 15 20:29:12 2002 @@ -6,7 +6,7 @@ * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * MPI_TARG.H Version: 01.02.06 + * MPI_TARG.H Version: 01.02.07 * * Version History * --------------- @@ -39,6 +39,8 @@ * 05-31-02 01.02.06 Modified TARGET_MODE_REPLY_ALIAS_MASK to only include * one bit. * Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER. + * 09-16-02 01.02.07 Added flags for confirmed completion. + * Added PRIORITY_REASON_TARGET_BUSY. * -------------------------------------------------------------------------- */ @@ -138,6 +140,7 @@ #define PRIORITY_REASON_PROTOCOL_ERR (0x06) #define PRIORITY_REASON_DATA_OUT_PARITY_ERR (0x07) #define PRIORITY_REASON_DATA_OUT_CRC_ERR (0x08) +#define PRIORITY_REASON_TARGET_BUSY (0x09) #define PRIORITY_REASON_UNKNOWN (0xFF) @@ -217,6 +220,7 @@ #define TARGET_ASSIST_FLAGS_DATA_DIRECTION (0x01) #define TARGET_ASSIST_FLAGS_AUTO_STATUS (0x02) #define TARGET_ASSIST_FLAGS_HIGH_PRIORITY (0x04) +#define TARGET_ASSIST_FLAGS_CONFIRMED (0x08) #define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80) @@ -261,6 +265,7 @@ #define TARGET_STATUS_SEND_FLAGS_AUTO_GOOD_STATUS (0x01) #define TARGET_STATUS_SEND_FLAGS_HIGH_PRIORITY (0x04) +#define TARGET_STATUS_SEND_FLAGS_CONFIRMED (0x08) #define TARGET_STATUS_SEND_FLAGS_REPOST_CMD_BUFFER (0x80) /* diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c --- a/drivers/message/fusion/mptbase.c Tue Oct 15 20:29:13 2002 +++ b/drivers/message/fusion/mptbase.c Tue Oct 15 20:29:13 2002 @@ -49,7 +49,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.c,v 1.121 2002/07/23 18:56:59 pdelaney Exp $ + * $Id: mptbase.c,v 1.122 2002/10/03 13:10:11 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -1416,10 +1416,30 @@ else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { ioc->chip_type = FC929X; ioc->prod_name = "LSIFC929X"; + { + /* 929X Chip Fix. Set Split transactions level + * for PCIX. Set bits 5 - 6 to zero, turn on bit 4. + */ + u16 pcixcmd = 0; + pci_read_config_word(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0xFF9F; + pcixcmd |= 0x0010; + pci_write_config_word(pdev, 0x6a, pcixcmd); + } } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { ioc->chip_type = FC919X; ioc->prod_name = "LSIFC919X"; + { + /* 919X Chip Fix. Set Split transactions level + * for PCIX. Set bits 5 - 6 to zero, turn on bit 4. + */ + u16 pcixcmd = 0; + pci_read_config_word(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0xFF9F; + pcixcmd |= 0x0010; + pci_write_config_word(pdev, 0x6a, pcixcmd); + } } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { ioc->chip_type = C1030; diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h --- a/drivers/message/fusion/mptbase.h Tue Oct 15 20:29:12 2002 +++ b/drivers/message/fusion/mptbase.h Tue Oct 15 20:29:12 2002 @@ -13,7 +13,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.h,v 1.133 2002/09/05 22:30:09 pdelaney Exp $ + * $Id: mptbase.h,v 1.134 2002/10/03 13:10:12 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -80,8 +80,8 @@ #define COPYRIGHT "Copyright (c) 1999-2002 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "2.02.01.01" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.02.01.01" +#define MPT_LINUX_VERSION_COMMON "2.02.01.07" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.02.01.07" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -91,7 +91,7 @@ /* * Fusion MPT(linux) driver configurable stuff... */ -#define MPT_MAX_ADAPTERS 16 +#define MPT_MAX_ADAPTERS 18 #define MPT_MAX_PROTOCOL_DRIVERS 16 #define MPT_MAX_BUS 1 #define MPT_MAX_FC_DEVICES 255 @@ -397,8 +397,10 @@ ScsiCmndTracker SentQ; ScsiCmndTracker DoneQ; //--- LUN split here? +#ifdef MPT_SAVE_AUTOSENSE u8 sense[SCSI_STD_SENSE_BYTES]; /* 18 */ u8 rsvd2[2]; /* alignment */ +#endif u32 luns; /* Max LUNs is 32 */ u8 inq_data[SCSI_STD_INQUIRY_BYTES]; /* 36 */ u8 pad0[4]; @@ -424,7 +426,9 @@ #define MPT_TARGET_DEFAULT_DV_STATUS 0 #define MPT_TARGET_FLAGS_VALID_NEGO 0x01 #define MPT_TARGET_FLAGS_VALID_INQUIRY 0x02 +#ifdef MPT_SAVE_AUTOSENSE #define MPT_TARGET_FLAGS_VALID_SENSE 0x04 +#endif #define MPT_TARGET_FLAGS_Q_YES 0x08 #define MPT_TARGET_FLAGS_VALID_56 0x10 @@ -890,6 +894,8 @@ MPT_Q_TRACKER taskQ; /* TM request Q */ spinlock_t freedoneQlock; int taskQcnt; + int num_chain; /* Number of chain buffers */ + int max_sge; /* Max No of SGE*/ u8 numTMrequests; u8 tmPending; u8 resetPending; diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c --- a/drivers/message/fusion/mptctl.c Tue Oct 15 20:29:11 2002 +++ b/drivers/message/fusion/mptctl.c Tue Oct 15 20:29:11 2002 @@ -34,7 +34,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.c,v 1.59 2002/09/05 22:30:10 pdelaney Exp $ + * $Id: mptctl.c,v 1.60 2002/10/03 13:10:13 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -627,7 +627,7 @@ /* Test for Compaq-specific IOCTL's. */ if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) || - (cmd == CPQFCTS_GETDRIVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) || + (cmd == CPQFCTS_GETDRIVVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) || (cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS)) return mptctl_compaq_ioctl(file, cmd, arg); @@ -2406,7 +2406,7 @@ case CPQFCTS_GETPCIINFO: ret = mptctl_cpq_getpciinfo(arg); break; - case CPQFCTS_GETDRIVER: + case CPQFCTS_GETDRIVVER: ret = mptctl_cpq_getdriver(arg); break; case CPQFCTS_CTLR_STATUS: @@ -3180,7 +3180,7 @@ if (++where && err) goto out_fail; err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(CPQFCTS_GETDRIVER, NULL); + err = register_ioctl32_conversion(CPQFCTS_GETDRIVVER, NULL); if (++where && err) goto out_fail; err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL); if (++where && err) goto out_fail; @@ -3234,7 +3234,7 @@ unregister_ioctl32_conversion(MPTCOMMAND32); unregister_ioctl32_conversion(MPTFWDOWNLOAD32); unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO); - unregister_ioctl32_conversion(CPQFCTS_GETDRIVER); + unregister_ioctl32_conversion(CPQFCTS_GETDRIVVER); unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS); unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS); unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32); diff -Nru a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h --- a/drivers/message/fusion/mptctl.h Tue Oct 15 20:29:17 2002 +++ b/drivers/message/fusion/mptctl.h Tue Oct 15 20:29:17 2002 @@ -20,7 +20,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.h,v 1.10 2002/05/28 15:57:16 pdelaney Exp $ + * $Id: mptctl.h,v 1.11 2002/10/03 13:10:13 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -319,12 +319,12 @@ #define CPQFCTS_IOC_MAGIC 'Z' #define CPQFCTS_GETPCIINFO _IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct) -#define CPQFCTS_GETDRIVER _IOR(CPQFCTS_IOC_MAGIC, 2, int) +#define CPQFCTS_GETDRIVVER _IOR(CPQFCTS_IOC_MAGIC, 9, int) #define CPQFCTS_CTLR_STATUS _IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status) -#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS _IOR(CPQFCTS_IOC_MAGIC, 4, struct scsi_fctargaddress) -#define CPQFCTS_SCSI_PASSTHRU _IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ) +#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS _IOR(CPQFCTS_IOC_MAGIC, 13, struct scsi_fctargaddress) +#define CPQFCTS_SCSI_PASSTHRU _IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ) #if defined(__sparc__) && defined(__sparc_v9__) -#define CPQFCTS_SCSI_PASSTHRU32 _IOWR(CPQFCTS_IOC_MAGIC, 5, VENDOR_IOCTL_REQ32) +#define CPQFCTS_SCSI_PASSTHRU32 _IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ32) #endif typedef struct { diff -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c --- a/drivers/message/fusion/mptlan.c Tue Oct 15 20:29:17 2002 +++ b/drivers/message/fusion/mptlan.c Tue Oct 15 20:29:17 2002 @@ -132,7 +132,7 @@ u32 total_received; struct net_device_stats stats; /* Per device statistics */ - struct work_struct post_buckets_task; + struct mpt_work_struct post_buckets_task; unsigned long post_buckets_active; }; @@ -876,9 +876,22 @@ if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) schedule_work(&priv->post_buckets_task); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40) + schedule_task(&priv->post_buckets_task); +#else + queue_task(&priv->post_buckets_task, &tq_immediate); + mark_bh(IMMEDIATE_BH); +#endif } else { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) schedule_delayed_work(&priv->post_buckets_task, 1); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40) + schedule_task(&priv->post_buckets_task); +#else + queue_task(&priv->post_buckets_task, &tq_timer); +#endif dioprintk((KERN_INFO MYNAM ": post_buckets queued on " "timer.\n")); } @@ -1364,8 +1377,8 @@ priv->mpt_dev = mpt_dev; priv->pnum = pnum; - memset(&priv->post_buckets_task, 0, sizeof(struct work_struct)); - INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev); + memset(&priv->post_buckets_task, 0, sizeof(struct mpt_work_struct)); + MPT_INIT_WORK(&priv->post_buckets_task, mpt_lan_post_receive_buckets, dev); priv->post_buckets_active = 0; dlprintk((KERN_INFO MYNAM "@%d: bucketlen = %d\n", diff -Nru a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h --- a/drivers/message/fusion/mptlan.h Tue Oct 15 20:29:15 2002 +++ b/drivers/message/fusion/mptlan.h Tue Oct 15 20:29:15 2002 @@ -20,7 +20,11 @@ #include #include #include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) +#include +#else #include +#endif #include // #include diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c Tue Oct 15 20:29:16 2002 +++ b/drivers/message/fusion/mptscsih.c Tue Oct 15 20:29:16 2002 @@ -26,7 +26,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.c,v 1.101 2002/09/05 22:30:11 pdelaney Exp $ + * $Id: mptscsih.c,v 1.102 2002/10/03 13:10:14 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -76,7 +76,6 @@ #include /* for mdelay */ #include /* needed for in_interrupt() proto */ #include /* notifier code */ -#include #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" #include "../../scsi/sd.h" @@ -165,7 +164,6 @@ static int mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex); static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx); static int mptscsih_initChainBuffers (MPT_SCSI_HOST *hd, int init); - static void copy_sense_data(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply); #ifndef MPT_SCSI_USE_NEW_EH static void search_taskQ_for_cmd(Scsi_Cmnd *sc, MPT_SCSI_HOST *hd); @@ -184,7 +182,9 @@ static VirtDevice *mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen); void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); +#ifdef MPT_SAVE_AUTOSENSE static void clear_sense_flag(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); +#endif static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags); static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id); @@ -245,7 +245,7 @@ */ static spinlock_t mytaskQ_lock = SPIN_LOCK_UNLOCKED; static int mytaskQ_bh_active = 0; -static struct work_struct mptscsih_ptaskfoo; +static struct mpt_work_struct mptscsih_ptaskfoo; static atomic_t mpt_taskQdepth; #endif @@ -256,7 +256,7 @@ static spinlock_t dvtaskQ_lock = SPIN_LOCK_UNLOCKED; static int dvtaskQ_active = 0; static int dvtaskQ_release = 0; -static struct work_struct mptscsih_dvTask; +static struct mpt_work_struct mptscsih_dvTask; #endif /* @@ -352,7 +352,9 @@ dlen); } } +#ifdef MPT_SAVE_AUTOSENSE clear_sense_flag(hd, pScsiReq); +#endif } else { u32 xfer_cnt; u16 status; @@ -437,17 +439,21 @@ * precedence! */ sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; +#ifdef MPT_SAVE_AUTOSENSE clear_sense_flag(hd, pScsiReq); - if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { +#endif + if (scsi_state == 0) { + ; + } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* Have already saved the status and sense data */ ; - } else if (pScsiReply->SCSIState & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + } else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { /* What to do? */ sc->result = DID_SOFT_ERROR << 16; } - else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { + else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { /* Not real sure here either... */ sc->result = DID_RESET << 16; } @@ -488,9 +494,12 @@ case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; +#ifdef MPT_SAVE_AUTOSENSE clear_sense_flag(hd, pScsiReq); - - if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { +#endif + if (scsi_state == 0) { + ; + } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* * If running agains circa 200003dd 909 MPT f/w, * may get this (AUTOSENSE_VALID) for actual TASK_SET_FULL @@ -521,7 +530,7 @@ #endif } - else if (pScsiReply->SCSIState & + else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS) ) { /* @@ -529,11 +538,11 @@ */ sc->result = DID_SOFT_ERROR << 16; } - else if (pScsiReply->SCSIState & MPI_SCSI_STATE_TERMINATED) { + else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { /* Not real sure here either... */ sc->result = DID_RESET << 16; } - else if (pScsiReply->SCSIState & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) { + else if (scsi_state & MPI_SCSI_STATE_QUEUE_TAG_REJECTED) { /* Device Inq. data indicates that it supports * QTags, but rejects QTag messages. * This command completed OK. @@ -1024,21 +1033,13 @@ MPT_FRAME_HDR *chain; u8 *mem; unsigned long flags; - int sz, ii, numChain; + int sz, ii, num_chain; + int scale, num_sge; - - /* Chain buffer allocations - * Allocate and initialize tracker structures + /* ReqToChain size must equal the req_depth + * index = req_idx */ - if (hd->ioc->req_sz <= 64) - numChain = MPT_SG_REQ_64_SCALE * hd->ioc->req_depth; - else if (hd->ioc->req_sz <= 96) - numChain = MPT_SG_REQ_96_SCALE * hd->ioc->req_depth; - else - numChain = MPT_SG_REQ_128_SCALE * hd->ioc->req_depth; - - sz = numChain * sizeof(int); - + sz = hd->ioc->req_depth * sizeof(int); if (hd->ReqToChain == NULL) { mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) @@ -1050,6 +1051,38 @@ } memset(mem, 0xFF, sz); + + /* ChainToChain size must equal the total number + * of chain buffers to be allocated. + * index = chain_idx + * + * Calculate the number of chain buffers needed(plus 1) per I/O + * then multiply the the maximum number of simultaneous cmds + * + * num_sge = num sge in request frame + last chain buffer + * scale = num sge per chain buffer if no chain element + */ + scale = hd->ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); + if (sizeof(dma_addr_t) == sizeof(u64)) + num_sge = scale + (hd->ioc->req_sz - 60) / (sizeof(dma_addr_t) + sizeof(u32)); + else + num_sge = 1+ scale + (hd->ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32)); + + num_chain = 1; + while (hd->max_sge - num_sge > 0) { + num_chain++; + num_sge += (scale - 1); + } + num_chain++; + + if ((int) hd->ioc->chip_type > (int) FC929) + num_chain *= MPT_SCSI_CAN_QUEUE; + else + num_chain *= MPT_FC_CAN_QUEUE; + + hd->num_chain = num_chain; + + sz = num_chain * sizeof(int); if (hd->ChainToChain == NULL) { mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) @@ -1061,10 +1094,10 @@ } memset(mem, 0xFF, sz); + sz = num_chain * hd->ioc->req_sz; if (hd->ChainBuffer == NULL) { /* Allocate free chain buffer pool */ - sz = numChain * hd->ioc->req_sz; mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA); if (mem == NULL) return -1; @@ -1090,7 +1123,7 @@ /* Post the chain buffers to the FreeChainQ. */ mem = (u8 *)hd->ChainBuffer; - for (ii=0; ii < numChain; ii++) { + for (ii=0; ii < num_chain; ii++) { chain = (MPT_FRAME_HDR *) mem; Q_ADD_TAIL(&hd->FreeChainQ.head, &chain->u.frame.linkage, MPT_FRAME_HDR); mem += hd->ioc->req_sz; @@ -1227,7 +1260,7 @@ #endif sh = scsi_register(tpnt, sizeof(MPT_SCSI_HOST)); if (sh != NULL) { - mptscsih_save_flags(flags); + mptscsih_lock(this, flags); sh->io_port = 0; sh->n_io_port = 0; sh->irq = 0; @@ -1254,12 +1287,21 @@ } sh->max_lun = MPT_LAST_LUN + 1; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) + sh->max_sectors = MPT_SCSI_MAX_SECTORS; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) + sh->highmem_io = 1; +#endif sh->this_id = this->pfacts[portnum].PortSCSIID; /* OS entry to allow host drivers to force * a queue depth on a per device basis. */ sh->select_queue_depths = mptscsih_select_queue_depths; + /* Required entry. + */ + sh->unique_id = this->id; /* Verify that we won't exceed the maximum * number of chain buffers @@ -1291,10 +1333,11 @@ */ scsi_set_pci_device(sh, this->pcidev); - mptscsih_restore_flags(flags); + mptscsih_unlock(this, flags); hd = (MPT_SCSI_HOST *) sh->hostdata; hd->ioc = this; + hd->max_sge = sh->sg_tablesize; if ((int)this->chip_type > (int)FC929) hd->is_spi = 1; @@ -1534,7 +1577,6 @@ int szc2chain = 0; int szchain = 0; int szQ = 0; - int scale; /* Synchronize disk caches */ @@ -1542,13 +1584,6 @@ sz1 = sz2 = sz3 = 0; - if (hd->ioc->req_sz <= 64) - scale = MPT_SG_REQ_64_SCALE; - else if (hd->ioc->req_sz <= 96) - scale = MPT_SG_REQ_96_SCALE; - else - scale = MPT_SG_REQ_128_SCALE; - if (hd->ScsiLookup != NULL) { sz1 = hd->ioc->req_depth * sizeof(void *); kfree(hd->ScsiLookup); @@ -1556,19 +1591,19 @@ } if (hd->ReqToChain != NULL) { - szr2chain = scale * hd->ioc->req_depth * sizeof(int); + szr2chain = hd->ioc->req_depth * sizeof(int); kfree(hd->ReqToChain); hd->ReqToChain = NULL; } if (hd->ChainToChain != NULL) { - szc2chain = scale * hd->ioc->req_depth * sizeof(int); + szc2chain = hd->num_chain * sizeof(int); kfree(hd->ChainToChain); hd->ChainToChain = NULL; } if (hd->ChainBuffer != NULL) { - sz2 = scale * hd->ioc->req_depth * hd->ioc->req_sz; + sz2 = hd->num_chain * hd->ioc->req_sz; szchain = szr2chain + szc2chain + sz2; pci_free_consistent(hd->ioc->pcidev, sz2, @@ -1591,7 +1626,7 @@ if (hd->is_spi) { max = MPT_MAX_SCSI_DEVICES; } else { - max = MPT_MAX_FC_DEVICES; + max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; } for (ii=0; ii < max; ii++) { if (hd->Targets[ii]) { @@ -1805,6 +1840,7 @@ dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); +#ifdef MPT_SAVE_AUTOSENSE /* 20000617 -sralston * GRRRRR... Shouldn't have to do this but... * Do explicit check for REQUEST_SENSE and cached SenseData. @@ -1840,6 +1876,7 @@ } } } +#endif if (hd->resetPending) { /* Prevent new commands from being issued @@ -2020,7 +2057,8 @@ if (!dvtaskQ_active) { dvtaskQ_active = 1; spin_unlock_irqrestore(&dvtaskQ_lock, lflags); - INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); + MPT_INIT_WORK(&mptscsih_dvTask, mptscsih_domainValidation, (void *) hd); + SCHEDULE_TASK(&mptscsih_dvTask); } else { spin_unlock_irqrestore(&dvtaskQ_lock, lflags); @@ -3046,7 +3084,7 @@ { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; - struct work_struct *ptaskfoo; + struct mpt_work_struct *ptaskfoo; unsigned long flags; int scpnt_idx; @@ -3154,10 +3192,8 @@ * Oh how cute, no alloc/free/mgmt needed if we use * (bottom/unused portion of) MPT request frame. */ - ptaskfoo = (struct work_struct *) &mptscsih_ptaskfoo; - ptaskfoo->sync = 0; - ptaskfoo->routine = mptscsih_taskmgmt_bh; - ptaskfoo->data = SCpnt; + ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo; + MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); SCHEDULE_TASK(ptaskfoo); } else { @@ -3182,7 +3218,7 @@ { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; - struct work_struct *ptaskfoo; + struct mpt_work_struct *ptaskfoo; unsigned long flags; int scpnt_idx; @@ -3284,10 +3320,8 @@ * Oh how cute, no alloc/free/mgmt needed if we use * (bottom/unused portion of) MPT request frame. */ - ptaskfoo = (struct work_struct *) &mptscsih_ptaskfoo; - ptaskfoo->sync = 0; - ptaskfoo->routine = mptscsih_taskmgmt_bh; - ptaskfoo->data = SCpnt; + ptaskfoo = (struct mpt_work_struct *) &mptscsih_ptaskfoo; + MPT_INIT_WORK(&mptscsih_ptaskfoo, mptscsih_taskmgmt_bh, (void *) SCpnt); SCHEDULE_TASK(ptaskfoo); } else { @@ -3655,7 +3689,7 @@ if (hd->is_spi) max = MPT_MAX_SCSI_DEVICES; else - max = MPT_MAX_FC_DEVICES; + max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; for (ii=0; ii < max; ii++) { pTarget = hd->Targets[ii]; @@ -3801,6 +3835,7 @@ /* save sense data to the target device */ if (target) { +#ifdef MPT_SAVE_AUTOSENSE int sz; sz = MIN(pReq->SenseBufferLength, sense_count); @@ -3808,6 +3843,7 @@ sz = SCSI_STD_SENSE_BYTES; memcpy(target->sense, sense_data, sz); target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE; +#endif #ifdef ABORT_FIX if (sz >= SCSI_STD_SENSE_BYTES) { @@ -4491,6 +4527,7 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +#if 0 static int dump_sd(char *foo, unsigned char *sd) { int snsLen = 8 + SD_Additional_Sense_Length(sd); @@ -4503,6 +4540,7 @@ return l; } +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* Do ASC/ASCQ lookup/grindage to English readable string(s) */ @@ -4594,6 +4632,15 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* + * SCSI Information Report; desired output format... + *--- +SCSI Error: (iocnum:target_id:LUN) Status=02h (CHECK CONDITION) + Key=6h (UNIT ATTENTION); FRU=03h + ASC/ASCQ=29h/00h, "POWER ON, RESET, OR BUS DEVICE RESET OCCURRED" + CDB: 00 00 00 00 00 00 - TestUnitReady + *--- + */ +/* * SCSI Error Report; desired output format... *--- SCSI Error Report =-=-=-=-=-=-=-=-=-=-=-=-=-= (ioc0,scsi0:0) @@ -4617,6 +4664,22 @@ unsigned char ascq = SD_ASCQ(ioop->sensePtr); int l; + /* Change the error logging to only report errors on + * read and write commands. Ignore errors on other commands. + * Should this be configurable via proc? + */ + switch (ioop->cdbPtr[0]) { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + break; + default: + return 0; + } + /* * More quiet mode. * Filter out common, repetitive, warning-type errors... like: @@ -4627,6 +4690,7 @@ if (sk == SK_NO_SENSE) { return 0; } + if ( (sk==SK_UNIT_ATTENTION && asc==0x29 && (ascq==0x00 || ascq==0x01)) || (sk==SK_NOT_READY && asc==0x04 && (ascq==0x01 || ascq==0x02)) || (sk==SK_ILLEGAL_REQUEST && asc==0x25 && ascq==0x00) @@ -4681,20 +4745,12 @@ else if (mpt_ScsiOpcodesPtr) opstr = mpt_ScsiOpcodesPtr[ioop->cdbPtr[0]]; - l = sprintf(foo, "SCSI Error Report =-=-= (%s)\n" - " SCSI_Status=%02Xh (%s)\n" - " Original_CDB[]:", - ioop->DevIDStr, - ioop->SCSIStatus, - statstr); - l += dump_cdb(foo+l, ioop->cdbPtr); - if (opstr) - l += sprintf(foo+l, " - \"%s\"", opstr); - l += sprintf(foo+l, "\n SenseData[%02Xh]:", 8+SD_Additional_Sense_Length(ioop->sensePtr)); - l += dump_sd(foo+l, ioop->sensePtr); - l += sprintf(foo+l, "\n SenseKey=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", - sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); - + l = sprintf(foo, "SCSI Error: (%s) Status=%02Xh (%s)\n", + ioop->DevIDStr, + ioop->SCSIStatus, + statstr); + l += sprintf(foo+l, " Key=%Xh (%s); FRU=%02Xh\n ASC/ASCQ=%02Xh/%02Xh", + sk, skstr, SD_FRU(ioop->sensePtr), asc, ascq ); { const char *x1, *x2, *x3, *x4; x1 = x2 = x3 = x4 = ""; @@ -4706,11 +4762,11 @@ l += sprintf(foo+l, " %s%s%s%s", x1,x2,x3,x4); } } - -#if 0 - if (SPECIAL_ASCQ(asc,ascq)) - l += sprintf(foo+l, " (%02Xh)", ascq); -#endif + l += sprintf(foo+l, "\n CDB:"); + l += dump_cdb(foo+l, ioop->cdbPtr); + if (opstr) + l += sprintf(foo+l, " - \"%s\"", opstr); + l += sprintf(foo+l, "\n"); PrintF(("%s\n", foo)); @@ -4953,6 +5009,7 @@ return; } +#ifdef MPT_SAVE_AUTOSENSE /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Clear sense valid flag. @@ -4968,6 +5025,7 @@ return; } +#endif /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return. * Else set the NEED_DV flag after Read Capacity Issued (disks) @@ -5366,7 +5424,9 @@ /* If target struct exists, clear sense valid flag. */ +#ifdef MPT_SAVE_AUTOSENSE clear_sense_flag(hd, pReq); +#endif if (mr == NULL) { completionCode = MPT_SCANDV_GOOD; @@ -5418,7 +5478,9 @@ completionCode = MPT_SCANDV_SOME_ERROR; } else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) { +#ifdef MPT_SAVE_AUTOSENSE VirtDevice *target; +#endif u8 *sense_data; int sz; @@ -5433,12 +5495,14 @@ SCSI_STD_SENSE_BYTES); memcpy(hd->pLocal->sense, sense_data, sz); +#ifdef MPT_SAVE_AUTOSENSE target = hd->Targets[pReq->TargetID]; if (target) { memcpy(target->sense, sense_data, sz); target->tflags |= MPT_TARGET_FLAGS_VALID_SENSE; } +#endif ddvprintk((KERN_NOTICE " Check Condition, sense ptr %p\n", sense_data)); diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h --- a/drivers/message/fusion/mptscsih.h Tue Oct 15 20:29:23 2002 +++ b/drivers/message/fusion/mptscsih.h Tue Oct 15 20:29:23 2002 @@ -20,7 +20,7 @@ * (mailto:netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.h,v 1.18 2002/06/06 15:32:52 pdelaney Exp $ + * $Id: mptscsih.h,v 1.19 2002/10/03 13:10:15 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -77,7 +77,22 @@ #define MPT_SCSI_CAN_QUEUE MPT_FC_CAN_QUEUE #define MPT_SCSI_CMD_PER_LUN 7 +#define MPT_SCSI_MAX_SECTORS 8192 + +/* + * Set the MAX_SGE value based on user input. + */ +#ifdef CONFIG_FUSION_MAX_SGE +#if CONFIG_FUSION_MAX_SGE < 16 +#define MPT_SCSI_SG_DEPTH 16 +#elif CONFIG_FUSION_MAX_SGE > 128 +#define MPT_SCSI_SG_DEPTH 128 +#else +#define MPT_SCSI_SG_DEPTH CONFIG_FUSION_MAX_SGE +#endif +#else #define MPT_SCSI_SG_DEPTH 40 +#endif /* To disable domain validation, uncomment the * following line. No effect for FC devices. @@ -146,25 +161,39 @@ /* * tq_scheduler disappeared @ lk-2.4.0-test12 * (right when newly defined TQ_ACTIVE) + * tq_struct reworked in 2.5.41. Include workqueue.h. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) +# include +# include +#define SCHEDULE_TASK(x) \ + if (schedule_work(x) == 0) { \ + /*MOD_DEC_USE_COUNT*/; \ + } +#else #define HAVE_TQ_SCHED 1 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) # include # ifdef TQ_ACTIVE # undef HAVE_TQ_SCHED # endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40) +# undef HAVE_TQ_SCHED +#endif #endif #ifdef HAVE_TQ_SCHED #define SCHEDULE_TASK(x) \ /*MOD_INC_USE_COUNT*/; \ - schedule_work(x) + (x)->next = NULL; \ + queue_task(x, &tq_scheduler) #else #define SCHEDULE_TASK(x) \ /*MOD_INC_USE_COUNT*/; \ - if (schedule_work(x) == 0) { \ + if (schedule_task(x) == 0) { \ /*MOD_DEC_USE_COUNT*/; \ } #endif +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -236,6 +265,7 @@ can_queue: MPT_SCSI_CAN_QUEUE, \ this_id: -1, \ sg_tablesize: MPT_SCSI_SG_DEPTH, \ + max_sectors: MPT_SCSI_MAX_SECTORS, \ cmd_per_lun: MPT_SCSI_CMD_PER_LUN, \ unchecked_isa_dma: 0, \ use_clustering: ENABLE_CLUSTERING, \ diff -Nru a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c --- a/drivers/message/i2o/i2o_block.c Tue Oct 15 20:29:19 2002 +++ b/drivers/message/i2o/i2o_block.c Tue Oct 15 20:29:19 2002 @@ -1647,7 +1647,7 @@ } for (i = 0; i < MAX_I2OB; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(16); if (!disk) goto oom; i2o_disk[i] = disk; @@ -1679,7 +1679,6 @@ struct gendisk *disk = i2ob_disk + i; disk->major = MAJOR_NR; disk->first_minor = i<<4; - disk->minor_shift = 4; disk->fops = &i2ob_fops; sprintf(disk->disk_name, "i2o/hd%c", 'a' + i); } diff -Nru a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c --- a/drivers/message/i2o/i2o_scsi.c Tue Oct 15 20:29:14 2002 +++ b/drivers/message/i2o/i2o_scsi.c Tue Oct 15 20:29:14 2002 @@ -9,10 +9,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * For the purpose of avoiding doubt the preferred form of the work - * for making modifications shall be a standards compliant form such - * gzipped tar and not one requiring a proprietary or patent encumbered - * tool to unpack. + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open non patent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. * * Complications for I2O scsi * @@ -61,7 +62,7 @@ #include "../../scsi/sd.h" #include "i2o_scsi.h" -#define VERSION_STRING "Version 0.1.0" +#define VERSION_STRING "Version 0.1.1" #define dprintk(x) @@ -114,7 +115,10 @@ static int sg_chain_tag = 0; static int sg_max_frags = SG_MAX_FRAGS; -/* +/** + * i2o_retry_run - retry on timeout + * @f: unused + * * Retry congested frames. This actually needs pushing down into * i2o core. We should only bother the OSM with this when we can't * queue and retry the frame. Or perhaps we should call the OSM @@ -134,6 +138,13 @@ spin_unlock_irqrestore(&retry_lock, flags); } +/** + * flush_pending - empty the retry queue + * + * Turn each of the pending commands into a NOP and post it back + * to the controller to clear it. + */ + static void flush_pending(void) { int i; @@ -150,6 +161,20 @@ spin_unlock_irqrestore(&retry_lock, flags); } +/** + * i2o_scsi_reply - scsi message reply processor + * @h: our i2o handler + * @c: controller issuing the reply + * @msg: the message from the controller (mapped) + * + * Process reply messages (interrupts in normal scsi controller think). + * We can get a variety of messages to process. The normal path is + * scsi command completions. We must also deal with IOP failures, + * the reply to a bus reset and the reply to a LUN query. + * + * Locks: the queue lock is taken to call the completion handler + */ + static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg) { Scsi_Cmnd *current_command; @@ -227,7 +252,7 @@ dprintk(("i2o got a scsi reply %08X: ", m[0])); dprintk(("m[2]=%08X: ", m[2])); dprintk(("m[4]=%08X\n", m[4])); - + if(m[2]&0x80000000) { if(m[2]&0x40000000) @@ -236,7 +261,7 @@ lun_done=1; return; } - printk(KERN_ERR "i2o_scsi: bus reset reply.\n"); + printk(KERN_INFO "i2o_scsi: bus reset completed.\n"); return; } /* @@ -313,6 +338,18 @@ I2O_CLASS_SCSI_PERIPHERAL }; +/** + * i2o_find_lun - report the lun of an i2o device + * @c: i2o controller owning the device + * @d: i2o disk device + * @target: filled in with target id + * @lun: filled in with target lun + * + * Query an I2O device to find out its SCSI lun and target numbering. We + * don't currently handle some of the fancy SCSI-3 stuff although our + * querying is sufficient to do so. + */ + static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun) { u8 reply[8]; @@ -331,6 +368,19 @@ return 0; } +/** + * i2o_scsi_init - initialize an i2o device for scsi + * @c: i2o controller owning the device + * @d: scsi controller + * @shpnt: scsi device we wish it to become + * + * Enumerate the scsi peripheral/fibre channel peripheral class + * devices that are children of the controller. From that we build + * a translation map for the command queue code. Since I2O works on + * its own tid's we effectively have to think backwards to get what + * the midlayer wants + */ + static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt) { struct i2o_device *unit; @@ -391,6 +441,16 @@ } } +/** + * i2o_scsi_detect - probe for I2O scsi devices + * @tpnt: scsi layer template + * + * I2O is a little odd here. The I2O core already knows what the + * devices are. It also knows them by disk and tape as well as + * by controller. We register each I2O scsi class object as a + * scsi controller and then let the enumeration fake up the rest + */ + static int i2o_scsi_detect(Scsi_Host_Template * tpnt) { unsigned long flags; @@ -398,7 +458,7 @@ int i; int count; - printk("i2o_scsi.c: %s\n", VERSION_STRING); + printk(KERN_INFO "i2o_scsi.c: %s\n", VERSION_STRING); if(i2o_install_handler(&i2o_scsi_handler)<0) { @@ -409,14 +469,14 @@ if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL) { - printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); - printk("i2o_scsi: SG chaining DISABLED!\n"); + printk(KERN_INFO "i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); + printk(KERN_INFO "i2o_scsi: SG chaining DISABLED!\n"); sg_max_frags = 11; } else { - printk(" chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); - printk(" (%d byte buffers X %d can_queue X %d i2o controllers)\n", + printk(KERN_INFO " chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); + printk(KERN_INFO " (%d byte buffers X %d can_queue X %d i2o controllers)\n", SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers); sg_max_frags = SG_MAX_FRAGS; // 64 } @@ -456,14 +516,11 @@ shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); if(shpnt==NULL) continue; - save_flags(flags); - cli(); shpnt->unique_id = (u32)d; shpnt->io_port = 0; shpnt->n_io_port = 0; shpnt->irq = 0; shpnt->this_id = /* Good question */15; - restore_flags(flags); i2o_scsi_init(c, d, shpnt); count++; } @@ -509,6 +566,20 @@ return(&hostdata->controller->name[0]); } +/** + * i2o_scsi_queuecommand - queue a SCSI command + * @SCpnt: scsi command pointer + * @done: callback for completion + * + * Issue a scsi comamnd asynchronously. Return 0 on success or 1 if + * we hit an error (normally message queue congestion). The only + * minor complication here is that I2O deals with the device addressing + * so we have to map the bus/dev/lun back to an I2O handle as well + * as faking absent devices ourself. + * + * Locks: takes the controller lock on error path only + */ + static int i2o_scsi_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { int i; @@ -525,6 +596,7 @@ u32 len; u32 reqlen; u32 tag; + unsigned long flags; static int max_qd = 1; @@ -560,24 +632,22 @@ if(tid == -1) { SCpnt->result = DID_NO_CONNECT << 16; + spin_lock_irqsave(host->host_lock, flags); done(SCpnt); + spin_unlock_irqrestore(host->host_lock, flags); return 0; } dprintk(("Real scsi messages.\n")); - /* - * Obtain an I2O message. Right now we _have_ to obtain one - * until the scsi layer stuff is cleaned up. + * Obtain an I2O message. If there are none free then + * throw it back to the scsi layer */ - do - { - mb(); - m = le32_to_cpu(I2O_POST_READ32(c)); - } - while(m==0xFFFFFFFF); + m = le32_to_cpu(I2O_POST_READ32(c)); + if(m==0xFFFFFFFF) + return 1; msg = (u32 *)(c->mem_offset + m); @@ -603,7 +673,11 @@ { /* Unknown - kill the command */ SCpnt->result = DID_NO_CONNECT << 16; + + /* We must lock the request queue while completing */ + spin_lock_irqsave(host->host_lock, flags); done(SCpnt); + spin_unlock_irqrestore(host->host_lock, flags); return 0; } @@ -772,11 +846,25 @@ return 0; } +/** + * internal_done - legacy scsi glue + * @SCPnt: command + * + * Completion function for a synchronous command + */ + static void internal_done(Scsi_Cmnd * SCpnt) { SCpnt->SCp.Status++; } +/** + * i2o_scsi_command - issue a scsi command and wait + * @SCPnt: command + * + * Issue a SCSI command and wait for it to complete. + */ + static int i2o_scsi_command(Scsi_Cmnd * SCpnt) { i2o_scsi_queuecommand(SCpnt, internal_done); @@ -786,6 +874,17 @@ return SCpnt->result; } +/** + * i2o_scsi_abort - abort a running command + * @SCpnt: command to abort + * + * Ask the I2O controller to abort a command. This is an asynchrnous + * process and oru callback handler will see the command complete + * with an aborted message if it succeeds. + * + * Locks: no locks are held or needed + */ + int i2o_scsi_abort(Scsi_Cmnd * SCpnt) { struct i2o_controller *c; @@ -795,21 +894,24 @@ u32 m; int tid; - printk("i2o_scsi: Aborting command block.\n"); + printk(KERN_WARNING "i2o_scsi: Aborting command block.\n"); host = SCpnt->host; hostdata = (struct i2o_scsi_host *)host->hostdata; tid = hostdata->task[SCpnt->target][SCpnt->lun]; if(tid==-1) { - printk(KERN_ERR "impossible command to abort.\n"); - return SCSI_ABORT_NOT_RUNNING; + printk(KERN_ERR "i2o_scsi: Impossible command to abort!\n"); + return FAILED; } c = hostdata->controller; /* * Obtain an I2O message. Right now we _have_ to obtain one * until the scsi layer stuff is cleaned up. + * + * FIXME: we are in error context so we could sleep retry + * a bit and then bail in the improved scsi layer. */ do @@ -828,10 +930,21 @@ wmb(); i2o_post_message(c,m); wmb(); - return SCSI_ABORT_PENDING; + return SUCCESS; } -static int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +/** + * i2o_scsi_bus_reset - Issue a SCSI reset + * @SCpnt: the command that caused the reset + * + * Perform a SCSI bus reset operation. In I2O this is just a message + * we pass. I2O can do clever multi-initiator and shared reset stuff + * but we don't support this. + * + * Locks: called with no lock held, requires no locks. + */ + +static int i2o_scsi_bus_reset(Scsi_Cmnd * SCpnt) { int tid; struct i2o_controller *c; @@ -844,7 +957,7 @@ * Find the TID for the bus */ - printk("i2o_scsi: Attempting to reset the bus.\n"); + printk(KERN_WARNING "i2o_scsi: Attempting to reset the bus.\n"); host = SCpnt->host; hostdata = (struct i2o_scsi_host *)host->hostdata; @@ -875,11 +988,43 @@ __raw_writel(c->unit << 16 | tid, msg+12); wmb(); i2o_post_message(c,m); - return SCSI_RESET_PENDING; + return SUCCESS; } -/* - * This is anyones guess quite frankly. +/** + * i2o_scsi_host_reset - host reset callback + * @SCpnt: command causing the reset + * + * An I2O controller can be many things at once. While we can + * reset a controller the potential mess from doing so is vast, and + * it's better to simply hold on and pray + */ + +static int i2o_scsi_host_reset(Scsi_Cmnd * SCpnt) +{ + return FAILED; +} + +/** + * i2o_scsi_device_reset - device reset callback + * @SCpnt: command causing the reset + * + * I2O does not (AFAIK) support doing a device reset + */ + +static int i2o_scsi_device_reset(Scsi_Cmnd * SCpnt) +{ + return FAILED; +} + +/** + * i2o_scsi_bios_param - Invent disk geometry + * @disk: device + * @dev: block layer device + * @ip: geometry array + * + * This is anyones guess quite frankly. We use the same rules everyone + * else appears to and hope. It seems to work. */ static int i2o_scsi_bios_param(Disk * disk, struct block_device *dev, int *ip) diff -Nru a/drivers/message/i2o/i2o_scsi.h b/drivers/message/i2o/i2o_scsi.h --- a/drivers/message/i2o/i2o_scsi.h Tue Oct 15 20:29:16 2002 +++ b/drivers/message/i2o/i2o_scsi.h Tue Oct 15 20:29:16 2002 @@ -1,12 +1,6 @@ #ifndef _I2O_SCSI_H #define _I2O_SCSI_H -#if !defined(LINUX_VERSION_CODE) -#include -#endif - -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) - #include #include @@ -19,28 +13,32 @@ static int i2o_scsi_command(Scsi_Cmnd *); static int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int i2o_scsi_abort(Scsi_Cmnd *); -static int i2o_scsi_reset(Scsi_Cmnd *, unsigned int); +static int i2o_scsi_bus_reset(Scsi_Cmnd *); +static int i2o_scsi_host_reset(Scsi_Cmnd *); +static int i2o_scsi_device_reset(Scsi_Cmnd *); static int i2o_scsi_bios_param(Disk *, struct block_device *, int *); static int i2o_scsi_release(struct Scsi_Host *host); -#define I2OSCSI { \ - next: NULL, \ - proc_name: "i2o_scsi", \ - name: "I2O SCSI Layer", \ - detect: i2o_scsi_detect, \ - release: i2o_scsi_release, \ - info: i2o_scsi_info, \ - command: i2o_scsi_command, \ - queuecommand: i2o_scsi_queuecommand, \ - abort: i2o_scsi_abort, \ - reset: i2o_scsi_reset, \ - bios_param: i2o_scsi_bios_param, \ - can_queue: I2O_SCSI_CAN_QUEUE, \ - this_id: I2O_SCSI_ID, \ - sg_tablesize: 8, \ - cmd_per_lun: I2O_SCSI_CMD_PER_LUN, \ - unchecked_isa_dma: 0, \ - use_clustering: ENABLE_CLUSTERING \ +#define I2OSCSI { \ + next: NULL, \ + proc_name: "i2o_scsi", \ + name: "I2O SCSI Layer", \ + detect: i2o_scsi_detect, \ + release: i2o_scsi_release, \ + info: i2o_scsi_info, \ + command: i2o_scsi_command, \ + queuecommand: i2o_scsi_queuecommand, \ + eh_abort_handler: i2o_scsi_abort, \ + eh_bus_reset_handler: i2o_scsi_bus_reset, \ + eh_device_reset_handler: i2o_scsi_device_reset, \ + eh_host_reset_handler: i2o_scsi_host_reset, \ + bios_param: i2o_scsi_bios_param, \ + can_queue: I2O_SCSI_CAN_QUEUE, \ + this_id: I2O_SCSI_ID, \ + sg_tablesize: 8, \ + cmd_per_lun: I2O_SCSI_CMD_PER_LUN, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ } #endif diff -Nru a/drivers/mtd/Config.help b/drivers/mtd/Config.help --- a/drivers/mtd/Config.help Tue Oct 15 20:29:23 2002 +++ b/drivers/mtd/Config.help Tue Oct 15 20:29:23 2002 @@ -21,36 +21,62 @@ devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. +CONFIG_MTD_CONCAT + Support for concatenating several MTD devices into a single + (virtual) one. This allows you to have -for example- a JFFS(2) + file system spanning multiple physical flash chips. If unsure, + say 'Y'. + CONFIG_MTD_REDBOOT_PARTS RedBoot is a ROM monitor and bootloader which deals with multiple - 'images' in flash devices by putting a table in the last erase block - of the device, similar to a partition table, which gives the - offsets, lengths and names of all the images stored in the flash. + 'images' in flash devices by putting a table in the last erase + block of the device, similar to a partition table, which gives + the offsets, lengths and names of all the images stored in the + flash. If you need code which can detect and parse this table, and register MTD 'partitions' corresponding to each image in the table, enable - this option. + this option. 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. -CONFIG_MTD_BOOTLDR_PARTS - The Compaq bootldr deals with multiple 'images' in flash devices - by putting a table in one of the first erase blocks of the device, - similar to a partition table, which gives the offsets, lengths and - names of all the images stored in the flash. - - If you need code which can detect and parse this table, and register - MTD 'partitions' corresponding to each image in the table, enable - this option. - +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. + 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 example. + The format for the command line is as follows: + + mtdparts=[; := :[,] + := [@offset][][ro] + := unique id used in mapping driver/device + := 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 + names. + + Examples: + + 1 flash resource (mtd-id "sa1100"), with 1 single writable partition: + mtdparts=sa1100:- + + Same flash, but 2 named partitions, the first one being read-only: + mtdparts=sa1100:256k(ARMboot)ro,-(root) + + If unsure, say 'N'. + CONFIG_MTD_AFS_PARTS The ARM Firmware Suite allows the user to divide flash devices into multiple 'images'. Each such image has a header containing its name @@ -61,7 +87,7 @@ enable this option. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The + for your particular device. It won't happen automatically. The 'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example. CONFIG_MTD_DEBUG_VERBOSE diff -Nru a/drivers/mtd/Config.in b/drivers/mtd/Config.in --- a/drivers/mtd/Config.in Tue Oct 15 20:29:12 2002 +++ b/drivers/mtd/Config.in Tue Oct 15 20:29:12 2002 @@ -1,5 +1,5 @@ -# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $ +# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $ mainmenu_option next_comment comment 'Memory Technology Devices (MTD)' @@ -12,9 +12,10 @@ int ' Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0 fi dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD + dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS + dep_tristate ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate ' Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS fi diff -Nru a/drivers/mtd/Makefile b/drivers/mtd/Makefile --- a/drivers/mtd/Makefile Tue Oct 15 20:29:16 2002 +++ b/drivers/mtd/Makefile Tue Oct 15 20:29:16 2002 @@ -1,12 +1,12 @@ # # Makefile for the memory technology device drivers. # -# -# $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $ +# Based on: +# $Id: Makefile,v 1.66 2002/04/23 13:52:14 mag Exp $ -export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o +export-objs := mtdcore.o mtdpart.o redboot.o cmdline.o afs.o mtdconcat.o -obj-y += chips/ maps/ devices/ nand/ +obj-y += chips/ maps/ devices/ nand/ # *** BIG UGLY NOTE *** # @@ -26,9 +26,10 @@ # Core functionality. obj-$(CONFIG_MTD) += mtdcore.o +obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o -obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o +obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdline.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o # 'Users' - code which presents functionality to userspace. diff -Nru a/drivers/mtd/afs.c b/drivers/mtd/afs.c --- a/drivers/mtd/afs.c Tue Oct 15 20:29:21 2002 +++ b/drivers/mtd/afs.c Tue Oct 15 20:29:21 2002 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.6 2001/10/02 10:04:51 rmk Exp $ + $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $ ======================================================================*/ @@ -82,6 +82,12 @@ if (fs.signature != 0xa0ffff9f) ret = 1; + /* + * Don't touch the SIB. + */ + if (fs.type == 2) + ret = 1; + *iis_start = fs.image_info_base & mask; *img_start = fs.image_start & mask; @@ -163,6 +169,7 @@ if (!parts) return -ENOMEM; + memset(parts, 0, sz); str = (char *)(parts + idx); /* diff -Nru a/drivers/mtd/bootldr.c b/drivers/mtd/bootldr.c --- a/drivers/mtd/bootldr.c Tue Oct 15 20:29:21 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,214 +0,0 @@ -/* - * Read flash partition table from Compaq Bootloader - * - * Copyright 2001 Compaq Computer Corporation. - * - * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $ - * - * Use consistent with the GNU GPL is permitted, - * provided that this copyright notice is - * preserved in its entirety in all copies and derived works. - * - * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, - * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS - * FITNESS FOR ANY PARTICULAR PURPOSE. - * - */ - -/* - * Maintainer: Jamey Hicks (jamey.hicks@compaq.com) - */ - -#include -#include - -#include -#include -#include -#include - -#define FLASH_PARTITION_NAMELEN 32 -enum LFR_FLAGS { - LFR_SIZE_PREFIX = 1, /* prefix data with 4-byte size */ - LFR_PATCH_BOOTLDR = 2, /* patch bootloader's 0th instruction */ - LFR_KERNEL = 4, /* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */ - LFR_EXPAND = 8 /* expand partition size to fit rest of flash */ -}; - -// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it -// for now -#define MAX_NUM_PARTITIONS 8 -typedef struct FlashRegion { - char name[FLASH_PARTITION_NAMELEN]; - unsigned long base; - unsigned long size; - enum LFR_FLAGS flags; -} FlashRegion; - -typedef struct BootldrFlashPartitionTable { - int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */ - int npartitions; - struct FlashRegion partition[8]; -} BootldrFlashPartitionTable; - -#define BOOTLDR_MAGIC 0x646c7462 /* btld: marks a valid bootldr image */ -#define BOOTLDR_PARTITION_MAGIC 0x646c7470 /* btlp: marks a valid bootldr partition table in params sector */ - -#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */ -#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */ - -#define BOOTCAP_WAKEUP (1<<0) -#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */ -#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */ - -static struct BootldrFlashPartitionTable Table; -static struct BootldrFlashPartitionTable *partition_table = NULL; - - -int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts) -{ - struct mtd_partition *parts; - int ret, retlen, i; - int npartitions = 0; - long partition_table_offset; - long bootmagic = 0; - long bootcap = 0; - int namelen = 0; - - char *names; - -#if 0 - /* verify bootldr magic */ - ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic); - if (ret) - goto out; - if (bootmagic != BOOTLDR_MAGIC) - goto out; - /* see if bootldr supports partition tables and where to find the partition table */ - ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap); - if (ret) - goto out; - - if (!(bootcap & BOOTCAP_PARTITIONS)) - goto out; - if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR) - partition_table_offset = master->erasesize; - else - partition_table_offset = master->size - master->erasesize; - - printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset); - printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr); - - - /* Read the partition table */ - partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!partition_table) - return -ENOMEM; - - ret = master->read(master, partition_table_offset, - PAGE_SIZE, &retlen, (void *)partition_table); - if (ret) - goto out; - -#endif - if (!partition_table) - return -ENOMEM; - - - printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic); - printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions); - - - /* check for partition table magic number */ - if (partition_table->magic != BOOTLDR_PARTITION_MAGIC) - goto out; - npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)? - MAX_NUM_PARTITIONS:partition_table->npartitions; - - printk(__FUNCTION__ ": npartitions=%#x\n", npartitions); - - for (i = 0; i < npartitions; i++) { - namelen += strlen(partition_table->partition[i].name) + 1; - } - - parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL); - if (!parts) { - ret = -ENOMEM; - goto out; - } - names = (char *)&parts[npartitions]; - memset(parts, 0, sizeof(*parts)*npartitions + namelen); - - - - // from here we use the partition table - for (i = 0; i < npartitions; i++) { - struct FlashRegion *partition = &partition_table->partition[i]; - const char *name = partition->name; - parts[i].name = names; - names += strlen(name) + 1; - strcpy(parts[i].name, name); - - if (partition->flags & LFR_EXPAND) - parts[i].size = MTDPART_SIZ_FULL; - else - parts[i].size = partition->size; - parts[i].offset = partition->base; - parts[i].mask_flags = 0; - - printk(" partition %s o=%x s=%x\n", - parts[i].name, parts[i].offset, parts[i].size); - - } - - ret = npartitions; - *pparts = parts; - - out: -#if 0 - if (partition_table) - kfree(partition_table); -#endif - - return ret; -} - - -static int __init parse_tag_ptable(const struct tag *tag) -{ - char buf[128]; - int i; - int j; - - partition_table = &Table; - -#ifdef CONFIG_DEBUG_LL - sprintf(buf,"ptable: magic = = 0x%lx npartitions= %d \n", - tag->u.ptable.magic,tag->u.ptable.npartitions); - printascii(buf); - - for (i=0; iu.ptable.npartitions; i++){ - sprintf(buf,"ptable: partition name = %s base= 0x%lx size= 0x%lx flags= 0x%lx\n", - (char *) (&tag->u.ptable.partition[i].name[0]), - tag->u.ptable.partition[i].base, - tag->u.ptable.partition[i].size, - tag->u.ptable.partition[i].flags); - printascii(buf); - } -#endif - - memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) + - sizeof(struct FlashRegion)*tag->u.ptable.npartitions); - - - return 0; -} - -__tagtable(ATAG_PTABLE, parse_tag_ptable); - -EXPORT_SYMBOL(parse_bootldr_partitions); - - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Compaq Computer Corporation"); -MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions"); diff -Nru a/drivers/mtd/cmdline.c b/drivers/mtd/cmdline.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/cmdline.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,343 @@ +/* + * $Id: cmdline.c,v 1.4 2002/09/13 01:18:38 jamey Exp $ + * + * Read flash partition table from command line + * + * Copyright 2002 SYSGO Real-Time Solutions GmbH + * + * The format for the command line is as follows: + * + * mtdparts=[; := :[,] + * := [@offset][][ro] + * := unique id used in mapping driver/device + * := standard linux memsize OR "-" to denote all remaining space + * := '(' NAME ')' + * + * Examples: + * + * 1 NOR Flash, with 1 single writable partition: + * edb7312-nor:- + * + * 1 NOR Flash with 2 partitions, 1 NAND with one + * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) + */ + +#include +#include + +#include +#include +#include +#include + +/* error message prefix */ +#define ERRP "mtd: " + +/* debug macro */ +#if 0 +#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0) +#else +#define dbg(x) +#endif + + +/* special size referring to all the remaining space in a partition */ +#define SIZE_REMAINING 0xffffffff + +struct cmdline_mtd_partition { + struct cmdline_mtd_partition *next; + char *mtd_id; + int num_parts; + struct mtd_partition *parts; +}; + +/* mtdpart_setup() parses into here */ +static struct cmdline_mtd_partition *partitions; + +/* the command line passed to mtdpart_setupd() */ +static char *cmdline; +static int cmdline_parsed = 0; + +/* + * Parse one partition definition for an MTD. Since there can be many + * comma separated partition definitions, this function calls itself + * recursively until no more partition definitions are found. Nice side + * effect: the memory to keep the mtd_partition structs and the names + * is allocated upon the last definition being found. At that point the + * syntax has been verified ok. + */ +static struct mtd_partition * newpart(char *s, + char **retptr, + int *num_parts, + int this_part, + unsigned char **extra_mem_ptr, + int extra_mem_size) +{ + struct mtd_partition *parts; + unsigned long size; + unsigned long offset = 0; + char *name; + int name_len; + unsigned char *extra_mem; + char delim; + unsigned int mask_flags; + + /* fetch the partition size */ + if (*s == '-') + { /* assign all remaining space to this partition */ + size = SIZE_REMAINING; + s++; + } + else + { + size = memparse(s, &s); + if (size < PAGE_SIZE) + { + printk(KERN_ERR ERRP "partition size too small (%lx)\n", size); + return 0; + } + } + + /* fetch partition name and flags */ + mask_flags = 0; /* this is going to be a regular partition */ + delim = 0; + /* check for offset */ + if (*s == '@') + { + s++; + offset = memparse(s, &s); + } + /* now look for name */ + if (*s == '(') + { + delim = ')'; + } + if (delim) + { + char *p; + + name = ++s; + if ((p = strchr(name, delim)) == 0) + { + printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim); + return 0; + } + name_len = p - name; + s = p + 1; + } + else + { + name = NULL; + name_len = 13; /* Partition_000 */ + } + + /* record name length for memory allocation later */ + extra_mem_size += name_len + 1; + + /* test for options */ + if (strncmp(s, "ro", 2) == 0) + { + mask_flags |= MTD_WRITEABLE; + s += 2; + } + + /* test if more partitions are following */ + if (*s == ',') + { + if (size == SIZE_REMAINING) + { + printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n"); + return 0; + } + /* more partitions follow, parse them */ + if ((parts = newpart(s + 1, &s, num_parts, + this_part + 1, &extra_mem, extra_mem_size)) == 0) + return 0; + } + else + { /* this is the last partition: allocate space for all */ + int alloc_size; + + *num_parts = this_part + 1; + alloc_size = *num_parts * sizeof(struct mtd_partition) + + extra_mem_size; + parts = kmalloc(alloc_size, GFP_KERNEL); + if (!parts) + { + printk(KERN_ERR ERRP "out of memory\n"); + return 0; + } + memset(parts, 0, alloc_size); + extra_mem = (unsigned char *)(parts + *num_parts); + } + /* enter this partition (offset will be calculated later if it is zero at this point) */ + parts[this_part].size = size; + parts[this_part].offset = offset; + parts[this_part].mask_flags = mask_flags; + if (name) + { + strncpy(extra_mem, name, name_len); + extra_mem[name_len] = 0; + } + else + { + sprintf(extra_mem, "Partition_%03d", this_part); + } + parts[this_part].name = extra_mem; + extra_mem += name_len + 1; + + dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", + this_part, + parts[this_part].name, + parts[this_part].offset, + parts[this_part].size, + parts[this_part].mask_flags)); + + /* return (updated) pointer to extra_mem memory */ + if (extra_mem_ptr) + *extra_mem_ptr = extra_mem; + + /* return (updated) pointer command line string */ + *retptr = s; + + /* return partition table */ + return parts; +} + +/* + * Parse the command line. + */ +static int mtdpart_setup_real(char *s) +{ + cmdline_parsed = 1; + + for( ; s != NULL; ) + { + struct cmdline_mtd_partition *this_mtd; + struct mtd_partition *parts; + int mtd_id_len; + int num_parts; + char *p, *mtd_id; + + mtd_id = s; + /* fetch */ + if (!(p = strchr(s, ':'))) + { + printk(KERN_ERR ERRP "no mtd-id\n"); + return 0; + } + mtd_id_len = p - mtd_id; + + dbg(("parsing <%s>\n", p+1)); + + /* + * parse one mtd. have it reserve memory for the + * struct cmdline_mtd_partition and the mtd-id string. + */ + parts = newpart(p + 1, /* cmdline */ + &s, /* out: updated cmdline ptr */ + &num_parts, /* out: number of parts */ + 0, /* first partition */ + (unsigned char**)&this_mtd, /* out: extra mem */ + mtd_id_len + 1 + sizeof(*this_mtd)); + + /* enter results */ + this_mtd->parts = parts; + this_mtd->num_parts = num_parts; + this_mtd->mtd_id = (char*)(this_mtd + 1); + strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len); + this_mtd->mtd_id[mtd_id_len] = 0; + + /* link into chain */ + this_mtd->next = partitions; + partitions = this_mtd; + + dbg(("mtdid=<%s> num_parts=<%d>\n", + this_mtd->mtd_id, this_mtd->num_parts)); + + + /* EOS - we're done */ + if (*s == 0) + break; + + /* does another spec follow? */ + if (*s != ';') + { + printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s); + return 0; + } + s++; + } + return 1; +} + +/* + * Main function to be called from the MTD mapping driver/device to + * obtain the partitioning information. At this point the command line + * arguments will actually be parsed and turned to struct mtd_partition + * information. + */ +int parse_cmdline_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + const char *mtd_id) +{ + unsigned long offset; + int i; + struct cmdline_mtd_partition *part; + + if (!cmdline) + return -EINVAL; + + /* parse command line */ + if (!cmdline_parsed) + mtdpart_setup_real(cmdline); + + for(part = partitions; part; part = part->next) + { + if (!strcmp(part->mtd_id, mtd_id)) + { + for(i = 0, offset = 0; i < part->num_parts; i++) + { + if (!part->parts[i].offset) + part->parts[i].offset = offset; + else + offset = part->parts[i].offset; + if (part->parts[i].size == SIZE_REMAINING) + part->parts[i].size = master->size - offset; + if (offset + part->parts[i].size > master->size) + { + printk(KERN_WARNING ERRP + "%s: partitioning exceeds flash size, truncating\n", + mtd_id); + part->parts[i].size = master->size - offset; + part->num_parts = i; + } + offset += part->parts[i].size; + } + *pparts = part->parts; + return part->num_parts; + } + } + return -EINVAL; +} + + +/* + * This is the handler for our kernel parameter, called from + * main.c::checksetup(). Note that we can not yet kmalloc() anything, + * so we only save the commandline for later processing. + */ +static int __init mtdpart_setup(char *s) +{ + cmdline = s; + return 1; +} + +__setup("mtdparts=", mtdpart_setup); + +EXPORT_SYMBOL(parse_cmdline_partitions); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marius Groeger "); +MODULE_DESCRIPTION("Command line configuration of MTD partitions"); diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c --- a/drivers/mtd/ftl.c Tue Oct 15 20:29:15 2002 +++ b/drivers/mtd/ftl.c Tue Oct 15 20:29:15 2002 @@ -1223,7 +1223,7 @@ } partition = kmalloc(sizeof(partition_t), GFP_KERNEL); - disk = alloc_disk(); + disk = alloc_disk(1 << PART_BITS); if (!partition||!disk) { printk(KERN_WARNING "No memory to scan for FTL on %s\n", @@ -1237,7 +1237,6 @@ sprintf(disk->disk_name, "ftl%c", 'a' + device); disk->major = FTL_MAJOR; disk->first_minor = device << 4; - disk->minor_shift = PART_BITS; disk->fops = &ftl_blk_fops; partition->mtd = mtd; partition->disk = disk; diff -Nru a/drivers/mtd/maps/Config.help b/drivers/mtd/maps/Config.help --- a/drivers/mtd/maps/Config.help Tue Oct 15 20:29:15 2002 +++ b/drivers/mtd/maps/Config.help Tue Oct 15 20:29:15 2002 @@ -1,3 +1,32 @@ +CONFIG_MTD_CDB89712 + This enables access to the flash or ROM chips on the CDB89712 board. + If you have such a board, say 'Y'. + +CONFIG_MTD_CEIVA + This enables access to the flash chips on the Ceiva/Polaroid + PhotoMax Digital Picture Frame. + If you have such a device, say 'Y'. + +CONFIG_MTD_FORTUNET + This enables access to the Flash on the FortuNet board. If you + have such a board, say 'Y'. + +CONFIG_MTD_AUTCPU12 + This enables access to the NV-RAM on autronix autcpu12 board. + If you have such a board, say 'Y'. + +CONFIG_MTD_EDB7312 + This enables access to the CFI Flash on the Cogent EDB7312 board. + If you have such a board, say 'Y' here. + +CONFIG_MTD_NAND_EDB7312 + This enables access to the NAND Flash on the Cogent EDB7312 board. + If you have such a board, say 'Y' here. + +CONFIG_MTD_IMPA7 + This enables access to the NOR Flash on the impA7 board of + implementa GmbH. If you have such a board, say 'Y' here. + CONFIG_MTD_SA1100 This enables access to the flash chips on most platforms based on the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. @@ -39,6 +68,12 @@ CONFIG_MTD_NORA If you had to ask, you don't have one. Say 'N'. +CONFIG_MTD_L440GX + Support for treating the BIOS flash chip on Intel L440GX motherboards + as an MTD device - with this you can reprogram your BIOS. + + BE VERY CAREFUL. + CONFIG_MTD_PNC2000 PNC-2000 is the name of Network Camera product from PHOTRON Ltd. in Japan. It uses CFI-compliant flash. @@ -50,6 +85,13 @@ to communicate with the chips on the RPXLite board. More at . +CONFIG_MTD_TQM8XXL + The TQM8xxL PowerPC board has up to two banks of CFI-compliant + chips, currently uses AMD one. This 'mapping' driver supports + that arrangement, allowing the CFI probe and command set driver + code to communicate with the chips on the TQM8xxL board. More at + . + CONFIG_MTD_SC520CDP The SC520 CDP board has two banks of CFI-compliant chips and one Dual-in-line JEDEC chip. This 'mapping' driver supports that @@ -59,7 +101,7 @@ This provides a driver for the on-board flash of Arcom Control Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX. By default the flash is split into 3 partitions which are accessed - as separate MTD devices. This board utilizes Intel StrataFlash. + as separate MTD devices. This board utilizes Intel StrataFlash. More info at . @@ -78,6 +120,11 @@ demonstration board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. +CONFIG_MTD_OCELOT + This enables access routines for the boot flash device and for the + NVRAM on the Momenco Ocelot board. If you have one of these boards + and would like access to either of these, say 'Y'. + CONFIG_MTD_ELAN_104NC This provides a driver for the on-board flash of the Arcom Control System's ELAN-104NC development board. By default the flash @@ -91,17 +138,17 @@ . CONFIG_MTD_CSTM_MIPS_IXX - This provides a mapping driver for the Integrated Tecnology Express, - Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference - Board. It provides the necessary addressing, length, buswidth, vpp - code and addition setup of the flash device for these boards. In - addition, this mapping driver can be used for other boards via - setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH - parameters. This mapping will provide one mtd device using one - partition. The start address can be offset from the beginning of - flash and the len can be less than the total flash device size to - allow a window into the flash. Both CFI and JEDEC probes are - called. + This provides a mapping driver for the Integrated Tecnology + Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR + Reference Board. It provides the necessary addressing, length, + buswidth, vpp code and addition setup of the flash device for + these boards. In addition, this mapping driver can be used for + other boards via setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/ + LEN/BUSWIDTH parameters. This mapping will provide one mtd device + using one partition. The start address can be offset from the + beginning of flash and the len can be less than the total flash + device size to allow a window into the flash. Both CFI and JEDEC + probes are called. CONFIG_MTD_CSTM_MIPS_IXX_START This is the physical memory location that the MTD driver will @@ -141,6 +188,11 @@ Computer. More information on the board is available at . +CONFIG_MTD_PCMCIA + Map driver for accessing PCMCIA linear flash memory cards. These + cards are usually around 4-16MiB in size. This does not include + Compact Flash cards which are treated as IDE devices. + CONFIG_MTD_VMAX This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Tempustech VMAX SBC301 Single @@ -148,32 +200,21 @@ . CONFIG_MTD_CFI_FLAGADM - Mapping for the Flaga digital module. If you don´t have one, ignore + Mapping for the Flaga digital module. If you don´t have one, ignore this setting. -CONFIG_MTD_OCELOT - This enables access routines for the boot flash device and for the - NVRAM on the Momenco Ocelot board. If you have one of these boards - and would like access to either of these, say 'Y'. - -CONFIG_MTD_CDB89712 - This enables access to the flash or ROM chips on the CDB89712 board. - If you have such a board, say 'Y'. - -CONFIG_MTD_L440GX - Support for treating the BIOS flash chip on Intel L440GX motherboards - as an MTD device - with this you can reprogram your BIOS. - - BE VERY CAREFUL. - CONFIG_MTD_SOLUTIONENGINE This enables access to the flash chips on the Hitachi SolutionEngine and similar boards. Say 'Y' if you are building a kernel for such a board. -CONFIG_MTD_TQM8XXL - The TQM8xxL PowerPC board has up to two banks of CFI-compliant - chips, currently uses AMD one. This 'mapping' driver supports - that arrangement, allowing the CFI probe and command set driver - code to communicate with the chips on the TQM8xxL board. More at - . +CONFIG_MTD_EPXA10DB + This enables support for the flash devices on the Altera + Excalibur XA10 Development Board. If you are building a kernel + for on of these boards then you should say 'Y' otherwise say 'N'. + +CONFIG_MTD_PCI + Mapping for accessing flash devices on add-in cards like the Intel XScale + IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode + (please see the manual for the link settings). + If you are not sure, say N. diff -Nru a/drivers/mtd/maps/Config.in b/drivers/mtd/maps/Config.in --- a/drivers/mtd/maps/Config.in Tue Oct 15 20:29:17 2002 +++ b/drivers/mtd/maps/Config.in Tue Oct 15 20:29:17 2002 @@ -56,8 +56,18 @@ dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712 dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS - dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS + dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310 + dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT + dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET + dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12 + dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI + dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE + dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA fi + +# This needs CFI or JEDEC, depending on the cards found. +dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI +dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA endmenu diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile Tue Oct 15 20:29:10 2002 +++ b/drivers/mtd/maps/Makefile Tue Oct 15 20:29:10 2002 @@ -4,29 +4,37 @@ # $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $ # Chip mappings -obj-$(CONFIG_MTD_CDB89712) += cdb89712.o +obj-$(CONFIG_MTD_CDB89712) += cdb89712.o obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o -obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o -obj-$(CONFIG_MTD_DC21285) += dc21285.o -obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o +obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o +obj-$(CONFIG_MTD_DC21285) += dc21285.o +obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o +obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o obj-$(CONFIG_MTD_L440GX) += l440gx.o obj-$(CONFIG_MTD_NORA) += nora.o +obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PNC2000) += pnc2000.o +obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o -obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o +obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o obj-$(CONFIG_MTD_NETSC520) += netsc520.o -obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o +obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o obj-$(CONFIG_MTD_VMAX) += vmax301.o obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o +obj-$(CONFIG_MTD_PCI) += pci.o +obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o +obj-$(CONFIG_MTD_EDB7312) += edb7312.o +obj-$(CONFIG_MTD_IMPA7) += impa7.o +obj-$(CONFIG_MTD_FORTUNET) += fortunet.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/autcpu12-nvram.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,179 @@ +/* + * NV-RAM memory access on autcpu12 + * (C) 2002 Thomas Gleixner (gleixner@autronix.de) + * + * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__u8 autcpu12_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +__u16 autcpu12_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +__u32 autcpu12_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + while(len) { + __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); + from++; + to++; + len--; + } +} + +static struct mtd_info *sram_mtd; + +struct map_info autcpu12_sram_map = { + name: "SRAM", + size: 32768, + buswidth: 8, + read8: autcpu12_read8, + read16: autcpu12_read16, + read32: autcpu12_read32, + copy_from: autcpu12_copy_from, + write8: autcpu12_write8, + write16: autcpu12_write16, + write32: autcpu12_write32, + copy_to: autcpu12_copy_to +}; + +static int __init init_autcpu12_sram (void) +{ + int err, save0, save1; + + autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K); + if (!autcpu12_sram_map.map_priv_1) { + printk("Failed to ioremap autcpu12 NV-RAM space\n"); + err = -EIO; + goto out; + } + + /* + * Check for 32K/128K + * read ofs 0 + * read ofs 0x10000 + * Write complement to ofs 0x100000 + * Read and check result on ofs 0x0 + * Restore contents + */ + save0 = autcpu12_read32(&autcpu12_sram_map,0); + save1 = autcpu12_read32(&autcpu12_sram_map,0x10000); + autcpu12_write32(&autcpu12_sram_map,~save0,0x10000); + /* if we find this pattern on 0x0, we have 32K size + * restore contents and exit + */ + if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) { + autcpu12_write32(&autcpu12_sram_map,save0,0x0); + goto map; + } + /* We have a 128K found, restore 0x10000 and set size + * to 128K + */ + autcpu12_write32(&autcpu12_sram_map,save1,0x10000); + autcpu12_sram_map.size = SZ_128K; + +map: + sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map); + if (!sram_mtd) { + printk("NV-RAM probe failed\n"); + err = -ENXIO; + goto out_ioremap; + } + + sram_mtd->module = THIS_MODULE; + sram_mtd->erasesize = 16; + + if (add_mtd_device(sram_mtd)) { + printk("NV-RAM device addition failed\n"); + err = -ENOMEM; + goto out_probe; + } + + printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); + + return 0; + +out_probe: + map_destroy(sram_mtd); + sram_mtd = 0; + +out_ioremap: + iounmap((void *)autcpu12_sram_map.map_priv_1); +out: + return err; +} + +static void __exit cleanup_autcpu12_maps(void) +{ + if (sram_mtd) { + del_mtd_device(sram_mtd); + map_destroy(sram_mtd); + iounmap((void *)autcpu12_sram_map.map_priv_1); + } +} + +module_init(init_autcpu12_sram); +module_exit(cleanup_autcpu12_maps); + +MODULE_AUTHOR("Thomas Gleixner"); +MODULE_DESCRIPTION("autcpu12 NV-RAM map driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/ceiva.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,408 @@ +/* + * Ceiva flash memory driver. + * Copyright (C) 2002 Rob Scott + * + * Note: this driver supports jedec compatible devices. Modification + * for CFI compatible devices should be straight forward: change + * jedec_probe to cfi_probe. + * + * Based on: sa1100-flash.c, which has the following copyright: + * Flash memory access on SA11x0 based devices + * + * (C) 2000 Nicolas Pitre + * + * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $ + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * This isnt complete yet, so... + */ +#define CONFIG_MTD_CEIVA_STATICMAP + +static __u8 clps_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +static __u16 clps_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +static __u32 clps_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void clps_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +static void clps_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +static void clps_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + +static struct map_info clps_map __initdata = { + name: "clps flash", + read8: clps_read8, + read16: clps_read16, + read32: clps_read32, + copy_from: clps_copy_from, + write8: clps_write8, + write16: clps_write16, + write32: clps_write32, + copy_to: clps_copy_to, +}; + +#ifdef CONFIG_MTD_CEIVA_STATICMAP +/* + * See include/linux/mtd/partitions.h for definition of the mtd_partition + * structure. + * + * Please note: + * 1. The flash size given should be the largest flash size that can + * be accomodated. + * + * 2. The bus width must defined in clps_setup_flash. + * + * The MTD layer will detect flash chip aliasing and reduce the size of + * the map accordingly. + * + */ + +#ifdef CONFIG_ARCH_CEIVA +/* Flash / Partition sizing */ +/* For the 28F8003, we use the block mapping to calcuate the sizes */ +#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128)) +#define BOOT_PARTITION_SIZE_KiB (16) +#define PARAMS_PARTITION_SIZE_KiB (8) +#define KERNEL_PARTITION_SIZE_KiB (4*128) +/* Use both remaing portion of first flash, and all of second flash */ +#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128) + +static struct mtd_partition ceiva_partitions[] = { + { + name: "Ceiva BOOT partition", + size: BOOT_PARTITION_SIZE_KiB*1024, + offset: 0, + + },{ + name: "Ceiva parameters partition", + size: PARAMS_PARTITION_SIZE_KiB*1024, + offset: (16 + 8) * 1024, + },{ + name: "Ceiva kernel partition", + size: (KERNEL_PARTITION_SIZE_KiB)*1024, + offset: 0x20000, + + },{ + name: "Ceiva root filesystem partition", + offset: MTDPART_OFS_APPEND, + size: (ROOT_PARTITION_SIZE_KiB)*1024, + } +}; +#endif + +static int __init clps_static_partitions(struct mtd_partition **parts) +{ + int nb_parts = 0; + +#ifdef CONFIG_ARCH_CEIVA + if (machine_is_ceiva()) { + *parts = ceiva_partitions; + nb_parts = ARRAY_SIZE(ceiva_partitions); + } +#endif + return nb_parts; +} +#endif + +struct clps_info { + unsigned long base; + unsigned long size; + int width; + void *vbase; + struct map_info *map; + struct mtd_info *mtd; + struct resource *res; +}; + +#define NR_SUBMTD 4 + +static struct clps_info info[NR_SUBMTD]; + +static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd) +{ + struct mtd_info *subdev[nr]; + struct map_info *maps; + int i, found = 0, ret = 0; + + /* + * Allocate the map_info structs in one go. + */ + maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); + if (!maps) + return -ENOMEM; + + /* + * Claim and then map the memory regions. + */ + for (i = 0; i < nr; i++) { + if (clps[i].base == (unsigned long)-1) + break; + + clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash"); + if (!clps[i].res) { + ret = -EBUSY; + break; + } + + clps[i].map = maps + i; + memcpy(clps[i].map, &clps_map, sizeof(struct map_info)); + + clps[i].vbase = ioremap(clps[i].base, clps[i].size); + if (!clps[i].vbase) { + ret = -ENOMEM; + break; + } + + clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase; + clps[i].map->buswidth = clps[i].width; + clps[i].map->size = clps[i].size; + + clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); + if (clps[i].mtd == NULL) { + ret = -ENXIO; + break; + } + clps[i].mtd->module = THIS_MODULE; + subdev[i] = clps[i].mtd; + + printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " + "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20, + clps[i].width * 8); + found += 1; + } + + /* + * ENXIO is special. It means we didn't find a chip when + * we probed. We need to tear down the mapping, free the + * resource and mark it as such. + */ + if (ret == -ENXIO) { + iounmap(clps[i].vbase); + clps[i].vbase = NULL; + release_resource(clps[i].res); + clps[i].res = NULL; + } + + /* + * If we found one device, don't bother with concat support. + * If we found multiple devices, use concat if we have it + * available, otherwise fail. + */ + if (ret == 0 || ret == -ENXIO) { + if (found == 1) { + *rmtd = subdev[0]; + ret = 0; + } else if (found > 1) { + /* + * We detected multiple devices. Concatenate + * them together. + */ +#ifdef CONFIG_MTD_CONCAT + *rmtd = mtd_concat_create(subdev, found, + "clps flash"); + if (*rmtd == NULL) + ret = -ENXIO; +#else + printk(KERN_ERR "clps flash: multiple devices " + "found but MTD concat support disabled.\n"); + ret = -ENXIO; +#endif + } + } + + /* + * If we failed, clean up. + */ + if (ret) { + do { + if (clps[i].mtd) + map_destroy(clps[i].mtd); + if (clps[i].vbase) + iounmap(clps[i].vbase); + if (clps[i].res) + release_resource(clps[i].res); + } while (i--); + + kfree(maps); + } + + return ret; +} + +static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd) +{ + int i; + + del_mtd_partitions(mtd); + + if (mtd != clps[0].mtd) + mtd_concat_destroy(mtd); + + for (i = NR_SUBMTD; i >= 0; i--) { + if (clps[i].mtd) + map_destroy(clps[i].mtd); + if (clps[i].vbase) + iounmap(clps[i].vbase); + if (clps[i].res) + release_resource(clps[i].res); + } + kfree(clps[0].map); +} + +/* + * We define the memory space, size, and width for the flash memory + * space here. + */ + +static int __init clps_setup_flash(void) +{ + int nr; + +#ifdef CONFIG_ARCH_CEIVA + if (machine_is_ceiva()) { + info[0].base = CS0_PHYS_BASE; + info[0].size = SZ_32M; + info[0].width = CEIVA_FLASH_WIDTH; + info[1].base = CS1_PHYS_BASE; + info[1].size = SZ_32M; + info[1].width = CEIVA_FLASH_WIDTH; + nr = 2; + } +#endif + return nr; +} + +extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); +extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); + +static struct mtd_partition *parsed_parts; + +static void __init clps_locate_partitions(struct mtd_info *mtd) +{ + const char *part_type = NULL; + int nr_parts = 0; + do { + /* + * Partition selection stuff. + */ +#ifdef CONFIG_MTD_CMDLINE_PARTS + nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps"); + if (nr_parts > 0) { + part_type = "command line"; + break; + } +#endif +#ifdef CONFIG_MTD_REDBOOT_PARTS + nr_parts = parse_redboot_partitions(mtd, &parsed_parts); + if (nr_parts > 0) { + part_type = "RedBoot"; + break; + } +#endif +#ifdef CONFIG_MTD_CEIVA_STATICMAP + nr_parts = clps_static_partitions(&parsed_parts); + if (nr_parts > 0) { + part_type = "static"; + break; + } + printk("found: %d partitions\n", nr_parts); +#endif + } while (0); + + if (nr_parts == 0) { + printk(KERN_NOTICE "clps flash: no partition info " + "available, registering whole flash\n"); + add_mtd_device(mtd); + } else { + printk(KERN_NOTICE "clps flash: using %s partition " + "definition\n", part_type); + add_mtd_partitions(mtd, parsed_parts, nr_parts); + } + + /* Always succeeds. */ +} + +static void __exit clps_destroy_partitions(void) +{ + if (parsed_parts) + kfree(parsed_parts); +} + +static struct mtd_info *mymtd; + +static int __init clps_mtd_init(void) +{ + int ret; + int nr; + + nr = clps_setup_flash(); + if (nr < 0) + return nr; + + ret = clps_setup_mtd(info, nr, &mymtd); + if (ret) + return ret; + + clps_locate_partitions(mymtd); + + return 0; +} + +static void __exit clps_mtd_cleanup(void) +{ + clps_destroy_mtd(info, mymtd); + clps_destroy_partitions(); +} + +module_init(clps_mtd_init); +module_exit(clps_mtd_cleanup); + +MODULE_AUTHOR("Rob Scott"); +MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c --- a/drivers/mtd/maps/dc21285.c Tue Oct 15 20:29:16 2002 +++ b/drivers/mtd/maps/dc21285.c Tue Oct 15 20:29:16 2002 @@ -5,9 +5,9 @@ * * This code is GPL * - * $Id: dc21285.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $ */ - +#include #include #include #include @@ -44,15 +44,15 @@ void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr) { - *CSR_ROMWRITEREG = adr; + *CSR_ROMWRITEREG = adr & 3; adr &= ~3; *(__u8*)(map->map_priv_1 + adr) = d; } void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr) { - *CSR_ROMWRITEREG = adr; - adr &= ~1; + *CSR_ROMWRITEREG = adr & 3; + adr &= ~3; *(__u16*)(map->map_priv_1 + adr) = d; } @@ -131,7 +131,7 @@ dc21285_map.buswidth*8); /* Let's map the flash area */ - dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0); + dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024); if (!dc21285_map.map_priv_1) { printk("Failed to ioremap\n"); return -EIO; @@ -139,20 +139,21 @@ mymtd = do_map_probe("cfi_probe", &dc21285_map); if (mymtd) { - int nrparts; + int nrparts = 0; mymtd->module = THIS_MODULE; /* partition fixup */ +#ifdef CONFIG_MTD_REDBOOT_PARTS nrparts = parse_redboot_partitions(mymtd, &dc21285_parts); - if (nrparts <=0) { +#endif + if (nrparts > 0) { + add_mtd_partitions(mymtd, dc21285_parts, nrparts); + } else if (nrparts == 0) { printk(KERN_NOTICE "RedBoot partition table failed\n"); - iounmap((void *)dc21285_map.map_priv_1); - return -ENXIO; + add_mtd_device(mymtd); } - - add_mtd_partitions(mymtd, dc21285_parts, nrparts); /* * Flash timing is determined with bits 19-16 of the diff -Nru a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/edb7312.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,202 @@ +/* + * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $ + * + * Handle mapping of the NOR flash on Cogent EDB7312 boards + * + * Copyright 2002 SYSGO Real-Time Solutions GmbH + * + * This program is free software; you can 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 + +#ifdef CONFIG_MTD_PARTITIONS +#include +#endif + +#define WINDOW_ADDR 0x00000000 /* physical properties of flash */ +#define WINDOW_SIZE 0x01000000 +#define BUSWIDTH 2 +#define FLASH_BLOCKSIZE_MAIN 0x20000 +#define FLASH_NUMBLOCKS_MAIN 128 +/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */ +#define PROBETYPES { "cfi_probe", 0 } + +#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */ +#define MTDID "edb7312-nor" /* for mtdparts= partitioning */ + +static struct mtd_info *mymtd; + +__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->map_priv_1 + to, from, len); +} + +struct map_info edb7312nor_map = { + name: "NOR flash on EDB7312", + size: WINDOW_SIZE, + buswidth: BUSWIDTH, + read8: edb7312nor_read8, + read16: edb7312nor_read16, + read32: edb7312nor_read32, + copy_from: edb7312nor_copy_from, + write8: edb7312nor_write8, + write16: edb7312nor_write16, + write32: edb7312nor_write32, + copy_to: edb7312nor_copy_to +}; + +#ifdef CONFIG_MTD_PARTITIONS + +/* + * MTD partitioning stuff + */ +static struct mtd_partition static_partitions[3] = +{ + { + name: "ARMboot", + size: 0x40000, + offset: 0 + }, + { + name: "Kernel", + size: 0x200000, + offset: 0x40000 + }, + { + name: "RootFS", + size: 0xDC0000, + offset: 0x240000 + }, +}; + +#define NB_OF(x) (sizeof (x) / sizeof (x[0])) + +#ifdef CONFIG_MTD_CMDLINE_PARTS +int parse_cmdline_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + const char *mtd_id); +#endif + +#endif + +static int mtd_parts_nb = 0; +static struct mtd_partition *mtd_parts = 0; + +int __init init_edb7312nor(void) +{ + static const char *rom_probe_types[] = PROBETYPES; + const char **type; + const char *part_type = 0; + + printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", + WINDOW_SIZE, WINDOW_ADDR); + edb7312nor_map.map_priv_1 = (unsigned long) + ioremap(WINDOW_ADDR, WINDOW_SIZE); + + if (!edb7312nor_map.map_priv_1) { + printk(MSG_PREFIX "failed to ioremap\n"); + return -EIO; + } + + mymtd = 0; + type = rom_probe_types; + for(; !mymtd && *type; type++) { + mymtd = do_map_probe(*type, &edb7312nor_map); + } + if (mymtd) { + mymtd->module = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID); + if (mtd_parts_nb > 0) + part_type = "command line"; +#endif + if (mtd_parts_nb == 0) + { + mtd_parts = static_partitions; + mtd_parts_nb = NB_OF(static_partitions); + part_type = "static"; + } +#endif + add_mtd_device(mymtd); + if (mtd_parts_nb == 0) + printk(KERN_NOTICE MSG_PREFIX "no partition info available\n"); + else + { + printk(KERN_NOTICE MSG_PREFIX + "using %s partition definition\n", part_type); + add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb); + } + return 0; + } + + iounmap((void *)edb7312nor_map.map_priv_1); + return -ENXIO; +} + +static void __exit cleanup_edb7312nor(void) +{ + if (mymtd) { + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (edb7312nor_map.map_priv_1) { + iounmap((void *)edb7312nor_map.map_priv_1); + edb7312nor_map.map_priv_1 = 0; + } +} + +module_init(init_edb7312nor); +module_exit(cleanup_edb7312nor); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marius Groeger "); +MODULE_DESCRIPTION("Generic configurable MTD map driver"); diff -Nru a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/epxa10db-flash.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,233 @@ +/* + * Flash memory access on EPXA based devices + * + * (C) 2000 Nicolas Pitre + * Copyright (C) 2001 Altera Corporation + * Copyright (C) 2001 Red Hat, Inc. + * + * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef CONFIG_EPXA10DB +#define BOARD_NAME "EPXA10DB" +#else +#define BOARD_NAME "EPXA1DB" +#endif + +static int nr_parts = 0; +static struct mtd_partition *parts; + +static struct mtd_info *mymtd; + +extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); +static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); + +static __u8 epxa_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +static __u16 epxa_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +static __u32 epxa_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); +} + +static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio((void *)(map->map_priv_1 + to), from, len); +} + + + +static struct map_info epxa_map = { + name: "EPXA flash", + size: FLASH_SIZE, + buswidth: 2, + read8: epxa_read8, + read16: epxa_read16, + read32: epxa_read32, + copy_from: epxa_copy_from, + write8: epxa_write8, + write16: epxa_write16, + write32: epxa_write32, + copy_to: epxa_copy_to +}; + + +static int __init epxa_mtd_init(void) +{ + int i; + + printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); + epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + if (!epxa_map.map_priv_1) { + printk("Failed to ioremap %s flash\n",BOARD_NAME); + return -EIO; + } + + mymtd = do_map_probe("cfi_probe", &epxa_map); + if (!mymtd) { + iounmap((void *)epxa_map.map_priv_1); + return -ENXIO; + } + + mymtd->module = THIS_MODULE; + + /* Unlock the flash device. */ + if(mymtd->unlock){ + for (i=0; inumeraseregions;i++){ + int j; + for(j=0;jeraseregions[i].numblocks;j++){ + mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize); + } + } + } + +#ifdef CONFIG_MTD_REDBOOT_PARTS + nr_parts = parse_redboot_partitions(mymtd, &parts); + + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } +#endif +#ifdef CONFIG_MTD_AFS_PARTS + nr_parts = parse_afs_partitions(mymtd, &parts); + + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } +#endif + + /* No recognised partitioning schemes found - use defaults */ + nr_parts = epxa_default_partitions(mymtd, &parts); + if (nr_parts > 0) { + add_mtd_partitions(mymtd, parts, nr_parts); + return 0; + } + + /* If all else fails... */ + add_mtd_device(mymtd); + return 0; +} + +static void __exit epxa_mtd_cleanup(void) +{ + if (mymtd) { + if (nr_parts) + del_mtd_partitions(mymtd); + else + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (epxa_map.map_priv_1) { + iounmap((void *)epxa_map.map_priv_1); + epxa_map.map_priv_1 = 0; + } +} + + +/* + * This will do for now, once we decide which bootldr we're finally + * going to use then we'll remove this function and do it properly + * + * Partions are currently (as offsets from base of flash): + * 0x00000000 - 0x003FFFFF - bootloader (!) + * 0x00400000 - 0x00FFFFFF - Flashdisk + */ + +static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts) +{ + struct mtd_partition *parts; + int ret, i; + int npartitions = 0; + char *names; + const char *name = "jffs"; + + printk("Using default partitions for %s\n",BOARD_NAME); + npartitions=1; + parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL); + memzero(parts,npartitions*sizeof(*parts)+strlen(name)); + if (!parts) { + ret = -ENOMEM; + goto out; + } + i=0; + names = (char *)&parts[npartitions]; + parts[i].name = names; + names += strlen(name) + 1; + strcpy(parts[i].name, name); + +#ifdef CONFIG_EPXA10DB + parts[i].size = FLASH_SIZE-0x00400000; + parts[i].offset = 0x00400000; +#else + parts[i].size = FLASH_SIZE-0x00180000; + parts[i].offset = 0x00180000; +#endif + + out: + *pparts = parts; + return npartitions; +} + + +module_init(epxa_mtd_init); +module_exit(epxa_mtd_cleanup); + +MODULE_AUTHOR("Clive Davies"); +MODULE_DESCRIPTION("Altera epxa mtd flash map"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/fortunet.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,309 @@ +/* fortunet.c memory map + * + * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NUM_REGIONS 4 +#define MAX_NUM_PARTITIONS 8 + +#define DEF_WINDOW_ADDR_PHY 0x00000000 +#define DEF_WINDOW_SIZE 0x00800000 // 8 Mega Bytes + +#define MTD_FORTUNET_PK "MTD FortuNet: " + +#define MAX_NAME_SIZE 128 + +struct map_region +{ + int window_addr_phyical; + int altbuswidth; + struct map_info map_info; + struct mtd_info *mymtd; + struct mtd_partition parts[MAX_NUM_PARTITIONS]; + char map_name[MAX_NAME_SIZE]; + char parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE]; +}; + +static struct map_region map_regions[MAX_NUM_REGIONS]; +static int map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0}; +static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0}; + + +__u8 fortunet_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +__u16 fortunet_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +__u32 fortunet_read32(struct map_info *map, unsigned long ofs) +{ + return *(__u32 *)(map->map_priv_1 + ofs); +} + +void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + +struct map_info default_map = { + size: DEF_WINDOW_SIZE, + buswidth: 4, + read8: fortunet_read8, + read16: fortunet_read16, + read32: fortunet_read32, + copy_from: fortunet_copy_from, + write8: fortunet_write8, + write16: fortunet_write16, + write32: fortunet_write32, + copy_to: fortunet_copy_to +}; + +static char * __init get_string_option(char *dest,int dest_size,char *sor) +{ + if(!dest_size) + return sor; + dest_size--; + while(*sor) + { + if(*sor==',') + { + sor++; + break; + } + else if(*sor=='\"') + { + sor++; + while(*sor) + { + if(*sor=='\"') + { + sor++; + break; + } + *dest = *sor; + dest++; + sor++; + dest_size--; + if(!dest_size) + { + *dest = 0; + return sor; + } + } + } + else + { + *dest = *sor; + dest++; + sor++; + dest_size--; + if(!dest_size) + { + *dest = 0; + return sor; + } + } + } + *dest = 0; + return sor; +} + +static int __init MTD_New_Region(char *line) +{ + char string[MAX_NAME_SIZE]; + int params[6]; + get_options (get_string_option(string,sizeof(string),line),6,params); + if(params[0]<1) + { + printk(MTD_FORTUNET_PK "Bad paramters for MTD Region " + " name,region-number[,base,size,buswidth,altbuswidth]\n"); + return 1; + } + if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS)) + { + printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n", + params[1],MAX_NUM_REGIONS-1); + return 1; + } + memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]])); + memcpy(&map_regions[params[1]].map_info, + &default_map,sizeof(map_regions[params[1]].map_info)); + map_regions_set[params[1]] = 1; + map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY; + map_regions[params[1]].altbuswidth = 2; + map_regions[params[1]].mymtd = NULL; + map_regions[params[1]].map_info.name = map_regions[params[1]].map_name; + strcpy(map_regions[params[1]].map_info.name,string); + if(params[0]>1) + { + map_regions[params[1]].window_addr_phyical = params[2]; + } + if(params[0]>2) + { + map_regions[params[1]].map_info.size = params[3]; + } + if(params[0]>3) + { + map_regions[params[1]].map_info.buswidth = params[4]; + } + if(params[0]>4) + { + map_regions[params[1]].altbuswidth = params[5]; + } + return 1; +} + +static int __init MTD_New_Partion(char *line) +{ + char string[MAX_NAME_SIZE]; + int params[4]; + get_options (get_string_option(string,sizeof(string),line),4,params); + if(params[0]<3) + { + printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion " + " name,region-number,size,offset\n"); + return 1; + } + if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS)) + { + printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n", + params[1],MAX_NUM_REGIONS-1); + return 1; + } + if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS) + { + printk(MTD_FORTUNET_PK "Out of space for partion in this region\n"); + return 1; + } + map_regions[params[1]].parts[map_regions_parts[params[1]]].name = + map_regions[params[1]]. parts_name[map_regions_parts[params[1]]]; + strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string); + map_regions[params[1]].parts[map_regions_parts[params[1]]].size = + params[2]; + map_regions[params[1]].parts[map_regions_parts[params[1]]].offset = + params[3]; + map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0; + map_regions_parts[params[1]]++; + return 1; +} + +__setup("MTD_Region=", MTD_New_Region); +__setup("MTD_Partion=", MTD_New_Partion); + +int __init init_fortunet(void) +{ + int ix,iy; + for(iy=ix=0;ixmodule = THIS_MODULE; + add_mtd_partitions(map_regions[ix].mymtd, + map_regions[ix].parts,map_regions_parts[ix]); + } + } + if(iy) + return 0; + return -ENXIO; +} + +static void __exit cleanup_fortunet(void) +{ + int ix; + for(ix=0;ix +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_MTD_PARTITIONS +#include +#endif + +#define WINDOW_ADDR0 0x00000000 /* physical properties of flash */ +#define WINDOW_SIZE0 0x00800000 +#define WINDOW_ADDR1 0x10000000 /* physical properties of flash */ +#define WINDOW_SIZE1 0x00800000 +#define NUM_FLASHBANKS 2 +#define BUSWIDTH 4 + +/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */ +#define PROBETYPES { "jedec_probe", 0 } + +#define MSG_PREFIX "impA7:" /* prefix for our printk()'s */ +#define MTDID "impa7-%d" /* for mtdparts= partitioning */ + +static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 }; + +__u8 impa7_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->map_priv_1 + ofs); +} + +__u16 impa7_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->map_priv_1 + ofs); +} + +__u32 impa7_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->map_priv_1 + ofs); +} + +void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->map_priv_1 + from, len); +} + +void impa7_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + __raw_writeb(d, map->map_priv_1 + adr); + mb(); +} + +void impa7_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + __raw_writew(d, map->map_priv_1 + adr); + mb(); +} + +void impa7_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + __raw_writel(d, map->map_priv_1 + adr); + mb(); +} + +void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->map_priv_1 + to, from, len); +} + +static struct map_info impa7_map[NUM_FLASHBANKS] = { + { + name: "impA7 NOR Flash Bank #0", + size: WINDOW_SIZE0, + buswidth: BUSWIDTH, + read8: impa7_read8, + read16: impa7_read16, + read32: impa7_read32, + copy_from: impa7_copy_from, + write8: impa7_write8, + write16: impa7_write16, + write32: impa7_write32, + copy_to: impa7_copy_to + }, + { + name: "impA7 NOR Flash Bank #1", + size: WINDOW_SIZE1, + buswidth: BUSWIDTH, + read8: impa7_read8, + read16: impa7_read16, + read32: impa7_read32, + copy_from: impa7_copy_from, + write8: impa7_write8, + write16: impa7_write16, + write32: impa7_write32, + copy_to: impa7_copy_to + }, +}; + +#ifdef CONFIG_MTD_PARTITIONS + +/* + * MTD partitioning stuff + */ +static struct mtd_partition static_partitions[] = +{ + { + name: "FileSystem", + size: 0x800000, + offset: 0x00000000 + }, +}; + +#define NB_OF(x) (sizeof (x) / sizeof (x[0])) + +#ifdef CONFIG_MTD_CMDLINE_PARTS +int parse_cmdline_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + const char *mtd_id); +#endif + +#endif + +static int mtd_parts_nb = 0; +static struct mtd_partition *mtd_parts = 0; + +int __init init_impa7(void) +{ + static const char *rom_probe_types[] = PROBETYPES; + const char **type; + const char *part_type = 0; + int i; + static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { + { WINDOW_ADDR0, WINDOW_SIZE0 }, + { WINDOW_ADDR1, WINDOW_SIZE1 }, + }; + char mtdid[10]; + int devicesfound = 0; + + for(i=0; imodule = THIS_MODULE; + add_mtd_device(impa7_mtd[i]); + devicesfound++; +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + sprintf(mtdid, MTDID, i); + mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], + &mtd_parts, + mtdid); + if (mtd_parts_nb > 0) + part_type = "command line"; +#endif + if (mtd_parts_nb <= 0) + { + mtd_parts = static_partitions; + mtd_parts_nb = NB_OF(static_partitions); + part_type = "static"; + } + if (mtd_parts_nb <= 0) + { + printk(KERN_NOTICE MSG_PREFIX + "no partition info available\n"); + } + else + { + printk(KERN_NOTICE MSG_PREFIX + "using %s partition definition\n", + part_type); + add_mtd_partitions(impa7_mtd[i], + mtd_parts, mtd_parts_nb); + } +#endif + } + else + iounmap((void *)impa7_map[i].map_priv_1); + } + return devicesfound == 0 ? -ENXIO : 0; +} + +static void __exit cleanup_impa7(void) +{ + int i; + for (i=0; i"); +MODULE_DESCRIPTION("MTD map driver for implementa impA7"); diff -Nru a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c --- a/drivers/mtd/maps/integrator-flash.c Tue Oct 15 20:29:20 2002 +++ b/drivers/mtd/maps/integrator-flash.c Tue Oct 15 20:29:20 2002 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.6 2001/10/02 16:00:01 dwmw2 Exp $ + $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $ ======================================================================*/ @@ -208,10 +208,10 @@ }; static struct mtd_info *mtd; +static struct mtd_partition *parts; static int __init armflash_cfi_init(void *base, u_int size) { - struct mtd_partition *parts; int ret; armflash_flash_init(); @@ -238,8 +238,6 @@ ret = parse_afs_partitions(mtd, &parts); if (ret > 0) { ret = add_mtd_partitions(mtd, parts, ret); - /* we don't need the partition info any longer */ - kfree(parts); if (ret) printk(KERN_ERR "mtd partition registration " "failed: %d\n", ret); @@ -262,6 +260,8 @@ del_mtd_partitions(mtd); map_destroy(mtd); } + if (parts) + kfree(parts); } static int __init armflash_init(void) diff -Nru a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c --- a/drivers/mtd/maps/iq80310.c Tue Oct 15 20:29:16 2002 +++ b/drivers/mtd/maps/iq80310.c Tue Oct 15 20:29:16 2002 @@ -1,5 +1,5 @@ /* - * $Id: iq80310.c,v 1.8 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $ * * Mapping for the Intel XScale IQ80310 evaluation board * @@ -116,7 +116,7 @@ int parsed_nr_parts = 0; char *part_type = "static"; - iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0); + iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); if (!iq80310_map.map_priv_1) { printk("Failed to ioremap\n"); return -EIO; @@ -161,7 +161,6 @@ } if (iq80310_map.map_priv_1) iounmap((void *)iq80310_map.map_priv_1); - return 0; } module_init(init_iq80310); diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/pci.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,385 @@ +/* + * linux/drivers/mtd/maps/pci.c + * + * Copyright (C) 2001 Russell King, All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $ + * + * Generic PCI memory map driver. We support the following boards: + * - Intel IQ80310 ATU. + * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001 + */ +#include +#include +#include +#include + +#include +#include +#include + +struct map_pci_info; + +struct mtd_pci_info { + int (*init)(struct pci_dev *dev, struct map_pci_info *map); + void (*exit)(struct pci_dev *dev, struct map_pci_info *map); + unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); + const char *map_name; +}; + +struct map_pci_info { + struct map_info map; + void *base; + void (*exit)(struct pci_dev *dev, struct map_pci_info *map); + unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs); + struct pci_dev *dev; +}; + +/* + * Intel IOP80310 Flash driver + */ + +static int +intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map) +{ + u32 win_base; + + map->map.buswidth = 1; + map->map.size = 0x00800000; + map->base = ioremap_nocache(pci_resource_start(dev, 0), + pci_resource_len(dev, 0)); + + if (!map->base) + return -ENOMEM; + + /* + * We want to base the memory window at Xscale + * bus address 0, not 0x1000. + */ + pci_read_config_dword(dev, 0x44, &win_base); + pci_write_config_dword(dev, 0x44, 0); + + map->map.map_priv_2 = win_base; + + return 0; +} + +static void +intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map) +{ + if (map->base) + iounmap((void *)map->base); + pci_write_config_dword(dev, 0x44, map->map.map_priv_2); +} + +static unsigned long +intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs) +{ + unsigned long page_addr = ofs & 0x00400000; + + /* + * This mundges the flash location so we avoid + * the first 80 bytes (they appear to read nonsense). + */ + if (page_addr) { + writel(0x00000008, map->base + 0x1558); + writel(0x00000000, map->base + 0x1550); + } else { + writel(0x00000007, map->base + 0x1558); + writel(0x00800000, map->base + 0x1550); + ofs += 0x00800000; + } + + return ofs; +} + +static struct mtd_pci_info intel_iq80310_info = { + init: intel_iq80310_init, + exit: intel_iq80310_exit, + translate: intel_iq80310_translate, + map_name: "cfi_probe", +}; + +/* + * Intel DC21285 driver + */ + +static int +intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map) +{ + unsigned long base, len; + + base = pci_resource_start(dev, PCI_ROM_RESOURCE); + len = pci_resource_len(dev, PCI_ROM_RESOURCE); + + if (!len || !base) { + /* + * No ROM resource + */ + base = pci_resource_start(dev, 2); + len = pci_resource_len(dev, 2); + + /* + * We need to re-allocate PCI BAR2 address range to the + * PCI ROM BAR, and disable PCI BAR2. + */ + } else { + /* + * Hmm, if an address was allocated to the ROM resource, but + * not enabled, should we be allocating a new resource for it + * or simply enabling it? + */ + if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) & + PCI_ROM_ADDRESS_ENABLE)) { + u32 val; + pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); + printk("%s: enabling expansion ROM\n", dev->slot_name); + } + } + + if (!len || !base) + return -ENXIO; + + map->map.buswidth = 4; + map->map.size = len; + map->base = ioremap_nocache(base, len); + + if (!map->base) + return -ENOMEM; + + return 0; +} + +static void +intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map) +{ + u32 val; + + if (map->base) + iounmap((void *)map->base); + + /* + * We need to undo the PCI BAR2/PCI ROM BAR address alteration. + */ + pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val); + val &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(dev, PCI_ROM_ADDRESS, val); +} + +static unsigned long +intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs) +{ + return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5)); +} + +static struct mtd_pci_info intel_dc21285_info = { + init: intel_dc21285_init, + exit: intel_dc21285_exit, + translate: intel_dc21285_translate, + map_name: "jedec_probe", +}; + +/* + * PCI device ID table + */ + +static struct pci_device_id mtd_pci_ids[] __devinitdata = { + { + vendor: PCI_VENDOR_ID_INTEL, + device: 0x530d, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + class: PCI_CLASS_MEMORY_OTHER << 8, + class_mask: 0xffff00, + driver_data: (unsigned long)&intel_iq80310_info, + }, + { + vendor: PCI_VENDOR_ID_DEC, + device: PCI_DEVICE_ID_DEC_21285, + subvendor: 0, /* DC21285 defaults to 0 on reset */ + subdevice: 0, /* DC21285 defaults to 0 on reset */ + class: 0, + class_mask: 0, + driver_data: (unsigned long)&intel_dc21285_info, + }, + { 0, } +}; + +/* + * Generic code follows. + */ + +static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u8 val = readb(map->base + map->translate(map, ofs)); +// printk("read8 : %08lx => %02x\n", ofs, val); + return val; +} + +static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u16 val = readw(map->base + map->translate(map, ofs)); +// printk("read16: %08lx => %04x\n", ofs, val); + return val; +} + +static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + u32 val = readl(map->base + map->translate(map, ofs)); +// printk("read32: %08lx => %08x\n", ofs, val); + return val; +} + +static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + memcpy_fromio(to, map->base + map->translate(map, from), len); +} + +static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write8 : %08lx <= %02x\n", ofs, val); + writeb(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write16: %08lx <= %04x\n", ofs, val); + writew(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; +// printk("write32: %08lx <= %08x\n", ofs, val); + writel(val, map->base + map->translate(map, ofs)); +} + +static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len) +{ + struct map_pci_info *map = (struct map_pci_info *)_map; + memcpy_toio(map->base + map->translate(map, to), from, len); +} + +static struct map_info mtd_pci_map = { + read8: mtd_pci_read8, + read16: mtd_pci_read16, + read32: mtd_pci_read32, + copy_from: mtd_pci_copyfrom, + write8: mtd_pci_write8, + write16: mtd_pci_write16, + write32: mtd_pci_write32, + copy_to: mtd_pci_copyto, +}; + +static int __devinit +mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data; + struct map_pci_info *map = NULL; + struct mtd_info *mtd = NULL; + int err; + + err = pci_enable_device(dev); + if (err) + goto out; + + err = pci_request_regions(dev, "pci mtd"); + if (err) + goto out; + + map = kmalloc(sizeof(*map), GFP_KERNEL); + err = -ENOMEM; + if (!map) + goto release; + + map->map = mtd_pci_map; + map->map.name = dev->slot_name; + map->dev = dev; + map->exit = info->exit; + map->translate = info->translate; + + err = info->init(dev, map); + if (err) + goto release; + + /* tsk - do_map_probe should take const char * */ + mtd = do_map_probe((char *)info->map_name, &map->map); + err = -ENODEV; + if (!mtd) + goto release; + + mtd->module = THIS_MODULE; + add_mtd_device(mtd); + + pci_set_drvdata(dev, mtd); + + return 0; + +release: + if (mtd) + map_destroy(mtd); + + if (map) { + map->exit(dev, map); + kfree(map); + } + + pci_release_regions(dev); +out: + return err; +} + +static void __devexit +mtd_pci_remove(struct pci_dev *dev) +{ + struct mtd_info *mtd = pci_get_drvdata(dev); + struct map_pci_info *map = mtd->priv; + + del_mtd_device(mtd); + map_destroy(mtd); + map->exit(dev, map); + kfree(map); + + pci_set_drvdata(dev, NULL); + pci_release_regions(dev); +} + +static struct pci_driver mtd_pci_driver = { + name: "MTD PCI", + probe: mtd_pci_probe, + remove: mtd_pci_remove, + id_table: mtd_pci_ids, +}; + +static int __init mtd_pci_maps_init(void) +{ + return pci_module_init(&mtd_pci_driver); +} + +static void __exit mtd_pci_maps_exit(void) +{ + pci_unregister_driver(&mtd_pci_driver); +} + +module_init(mtd_pci_maps_init); +module_exit(mtd_pci_maps_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("Generic PCI map driver"); +MODULE_DEVICE_TABLE(pci, mtd_pci_ids); + diff -Nru a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/pcmciamtd.c Tue Oct 15 20:29:24 2002 @@ -0,0 +1,893 @@ +/* + * $Id: pcmciamtd.c,v 1.36 2002/10/14 18:49:12 rmk Exp $ + * + * pcmciamtd.c - MTD driver for PCMCIA flash memory cards + * + * Author: Simon Evans + * + * Copyright (C) 2002 Simon Evans + * + * Licence: GPL + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_MTD_DEBUG +static int debug = CONFIG_MTD_DEBUG_VERBOSE; +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); +#undef DEBUG +#define DEBUG(n, format, arg...) \ + if (n <= debug) { \ + printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \ + } + +#else +#undef DEBUG +#define DEBUG(n, arg...) +static const int debug = 0; +#endif + +#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) +#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg) +#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg) + + +#define DRIVER_DESC "PCMCIA Flash memory card driver" +#define DRIVER_VERSION "$Revision: 1.36 $" + +/* Size of the PCMCIA address space: 26 bits = 64 MB */ +#define MAX_PCMCIA_ADDR 0x4000000 + +struct pcmciamtd_dev { + struct list_head list; + dev_link_t link; /* PCMCIA link */ + caddr_t win_base; /* ioremapped address of PCMCIA window */ + unsigned int win_size; /* size of window */ + unsigned int cardsize; /* size of whole card */ + unsigned int offset; /* offset into card the window currently points at */ + struct map_info pcmcia_map; + struct mtd_info *mtd_info; + u8 vpp; + char mtd_name[sizeof(struct cistpl_vers_1_t)]; +}; + + +static dev_info_t dev_info = "pcmciamtd"; +static LIST_HEAD(dev_list); + +/* Module parameters */ + +/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */ +static int buswidth = 2; + +/* Speed of memory accesses, in ns */ +static int mem_speed; + +/* Force the size of an SRAM card */ +static int force_size; + +/* Force Vpp */ +static int vpp; + +/* Set Vpp */ +static int setvpp; + +/* Force card to be treated as FLASH, ROM or RAM */ +static int mem_type; + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Simon Evans "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_PARM(buswidth, "i"); +MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)"); +MODULE_PARM(mem_speed, "i"); +MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns"); +MODULE_PARM(force_size, "i"); +MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)"); +MODULE_PARM(setvpp, "i"); +MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)"); +MODULE_PARM(vpp, "i"); +MODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)"); +MODULE_PARM(mem_type, "i"); +MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)"); + + + +static void inline cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + + +/* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */ + +static caddr_t remap_window(struct map_info *map, unsigned long to) +{ + struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; + window_handle_t win = (window_handle_t)map->map_priv_2; + memreq_t mrq; + int ret; + + mrq.CardOffset = to & ~(dev->win_size-1); + if(mrq.CardOffset != dev->offset) { + DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", + dev->offset, mrq.CardOffset); + mrq.Page = 0; + if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) { + cs_error(dev->link.handle, MapMemPage, ret); + return NULL; + } + dev->offset = mrq.CardOffset; + } + return dev->win_base + (to & (dev->win_size-1)); +} + + +static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs) +{ + caddr_t addr; + u8 d; + + addr = remap_window(map, ofs); + if(!addr) + return 0; + + d = readb(addr); + DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d); + return d; +} + + +static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs) +{ + caddr_t addr; + u16 d; + + addr = remap_window(map, ofs); + if(!addr) + return 0; + + d = readw(addr); + DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d); + return d; +} + + +static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; + unsigned long win_size = dev->win_size; + + DEBUG(3, "to = %p from = %lu len = %u", to, from, len); + while(len) { + int toread = win_size - (from & (win_size-1)); + caddr_t addr; + + if(toread > len) + toread = len; + + addr = remap_window(map, from); + if(!addr) + return; + + DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread); + memcpy_fromio(to, addr, toread); + len -= toread; + to += toread; + from += toread; + } +} + + +static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr) +{ + caddr_t addr = remap_window(map, adr); + + if(!addr) + return; + + DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, addr, d); + writeb(d, addr); +} + + +static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr) +{ + caddr_t addr = remap_window(map, adr); + if(!addr) + return; + + DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, addr, d); + writew(d, addr); +} + + +static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; + unsigned long win_size = dev->win_size; + + DEBUG(3, "to = %lu from = %p len = %u", to, from, len); + while(len) { + int towrite = win_size - (to & (win_size-1)); + caddr_t addr; + + if(towrite > len) + towrite = len; + + addr = remap_window(map, to); + if(!addr) + return; + + DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite); + memcpy_toio(addr, from, towrite); + len -= towrite; + to += towrite; + from += towrite; + } +} + + +/* read/write{8,16} copy_{from,to} routines with direct access */ + +static u8 pcmcia_read8(struct map_info *map, unsigned long ofs) +{ + caddr_t win_base = (caddr_t)map->map_priv_2; + u8 d; + + d = readb(win_base + ofs); + DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d); + return d; +} + + +static u16 pcmcia_read16(struct map_info *map, unsigned long ofs) +{ + caddr_t win_base = (caddr_t)map->map_priv_2; + u16 d; + + d = readw(win_base + ofs); + DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d); + return d; +} + + +static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + caddr_t win_base = (caddr_t)map->map_priv_2; + + DEBUG(3, "to = %p from = %lu len = %u", to, from, len); + memcpy_fromio(to, win_base + from, len); +} + + +static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr) +{ + caddr_t win_base = (caddr_t)map->map_priv_2; + + DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, win_base + adr, d); + writeb(d, win_base + adr); +} + + +static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr) +{ + caddr_t win_base = (caddr_t)map->map_priv_2; + + DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, win_base + adr, d); + writew(d, win_base + adr); +} + + +static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + caddr_t win_base = (caddr_t)map->map_priv_2; + + DEBUG(3, "to = %lu from = %p len = %u", to, from, len); + memcpy_toio(win_base + to, from, len); +} + + +static void pcmciamtd_set_vpp(struct map_info *map, int on) +{ + struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; + dev_link_t *link = &dev->link; + modconf_t mod; + int ret; + + mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID; + mod.Vcc = 0; + mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0; + + DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); + ret = CardServices(ModifyConfiguration, link->handle, &mod); + if(ret != CS_SUCCESS) { + cs_error(link->handle, ModifyConfiguration, ret); + } +} + + +/* After a card is removed, pcmciamtd_release() will unregister the + * device, and release the PCMCIA configuration. If the device is + * still open, this will be postponed until it is closed. + */ + +static void pcmciamtd_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct pcmciamtd_dev *dev = NULL; + int ret; + struct list_head *temp1, *temp2; + + DEBUG(3, "link = 0x%p", link); + /* Find device in list */ + list_for_each_safe(temp1, temp2, &dev_list) { + dev = list_entry(temp1, struct pcmciamtd_dev, list); + if(link == &dev->link) + break; + } + if(link != &dev->link) { + DEBUG(1, "Cant find %p in dev_list", link); + return; + } + + if(dev) { + if(dev->mtd_info) { + del_mtd_device(dev->mtd_info); + dev->mtd_info = NULL; + MOD_DEC_USE_COUNT; + } + if (link->win) { + if(dev->win_base) { + iounmap(dev->win_base); + dev->win_base = NULL; + } + CardServices(ReleaseWindow, link->win); + } + ret = CardServices(ReleaseConfiguration, link->handle); + if(ret != CS_SUCCESS) + cs_error(link->handle, ReleaseConfiguration, ret); + + } + link->state &= ~DEV_CONFIG; +} + + +static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name) +{ + int rc; + tuple_t tuple; + cisparse_t parse; + u_char buf[64]; + + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + tuple.DesiredTuple = RETURN_FIRST_TUPLE; + + rc = CardServices(GetFirstTuple, link->handle, &tuple); + while(rc == CS_SUCCESS) { + rc = CardServices(GetTupleData, link->handle, &tuple); + if(rc != CS_SUCCESS) { + cs_error(link->handle, GetTupleData, rc); + break; + } + rc = CardServices(ParseTuple, link->handle, &tuple, &parse); + if(rc != CS_SUCCESS) { + cs_error(link->handle, ParseTuple, rc); + break; + } + + switch(tuple.TupleCode) { + case CISTPL_FORMAT: { + cistpl_format_t *t = &parse.format; + (void)t; /* Shut up, gcc */ + DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", + t->type, t->edc, t->offset, t->length); + break; + + } + + case CISTPL_DEVICE: { + cistpl_device_t *t = &parse.device; + int i; + DEBUG(2, "Common memory:"); + dev->pcmcia_map.size = t->dev[0].size; + for(i = 0; i < t->ndev; i++) { + DEBUG(2, "Region %d, type = %u", i, t->dev[i].type); + DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp); + DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed); + DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size); + } + break; + } + + case CISTPL_VERS_1: { + cistpl_vers_1_t *t = &parse.version_1; + int i; + if(t->ns) { + dev->mtd_name[0] = '\0'; + for(i = 0; i < t->ns; i++) { + if(i) + strcat(dev->mtd_name, " "); + strcat(dev->mtd_name, t->str+t->ofs[i]); + } + } + DEBUG(2, "Found name: %s", dev->mtd_name); + break; + } + + case CISTPL_JEDEC_C: { + cistpl_jedec_t *t = &parse.jedec; + int i; + for(i = 0; i < t->nid; i++) { + DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info); + } + break; + } + + case CISTPL_DEVICE_GEO: { + cistpl_device_geo_t *t = &parse.device_geo; + int i; + dev->pcmcia_map.buswidth = t->geo[0].buswidth; + for(i = 0; i < t->ngeo; i++) { + DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth); + DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block); + DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block); + DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block); + DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition); + DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave); + } + break; + } + + default: + DEBUG(2, "Unknown tuple code %d", tuple.TupleCode); + } + + rc = CardServices(GetNextTuple, link->handle, &tuple, &parse); + } + if(!dev->pcmcia_map.size) + dev->pcmcia_map.size = MAX_PCMCIA_ADDR; + + if(!dev->pcmcia_map.buswidth) + dev->pcmcia_map.buswidth = 2; + + if(force_size) { + dev->pcmcia_map.size = force_size << 20; + DEBUG(2, "size forced to %dM", force_size); + + } + + if(buswidth) { + dev->pcmcia_map.buswidth = buswidth; + DEBUG(2, "buswidth forced to %d", buswidth); + } + + dev->pcmcia_map.name = dev->mtd_name; + if(!dev->mtd_name[0]) { + strcpy(dev->mtd_name, "PCMCIA Memory card"); + *new_name = 1; + } + + DEBUG(1, "Device: Size: %lu Width:%d Name: %s", + dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name); +} + + +/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event + * is received, to configure the PCMCIA socket, and to make the + * MTD device available to the system. + */ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void pcmciamtd_config(dev_link_t *link) +{ + struct pcmciamtd_dev *dev = link->priv; + struct mtd_info *mtd = NULL; + cs_status_t status; + win_req_t req; + int last_ret = 0, last_fn = 0; + int ret; + int i; + config_info_t t; + static char *probes[] = { "jedec_probe", "cfi_probe" }; + cisinfo_t cisinfo; + int new_name = 0; + + DEBUG(3, "link=0x%p", link); + + /* Configure card */ + link->state |= DEV_CONFIG; + + DEBUG(2, "Validating CIS"); + ret = CardServices(ValidateCIS, link->handle, &cisinfo); + if(ret != CS_SUCCESS) { + cs_error(link->handle, GetTupleData, ret); + } else { + DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains); + } + + card_settings(dev, link, &new_name); + + dev->pcmcia_map.read8 = pcmcia_read8_remap; + dev->pcmcia_map.read16 = pcmcia_read16_remap; + dev->pcmcia_map.copy_from = pcmcia_copy_from_remap; + dev->pcmcia_map.write8 = pcmcia_write8_remap; + dev->pcmcia_map.write16 = pcmcia_write16_remap; + dev->pcmcia_map.copy_to = pcmcia_copy_to_remap; + if(setvpp == 1) + dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp; + + /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum + that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the + whole card - otherwise we try smaller windows until we succeed */ + + req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE; + req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16; + req.Base = 0; + req.AccessSpeed = mem_speed; + link->win = (window_handle_t)link->handle; + req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR; + dev->win_size = 0; + + do { + int ret; + DEBUG(2, "requesting window with size = %dKB memspeed = %d", + req.Size >> 10, req.AccessSpeed); + link->win = (window_handle_t)link->handle; + ret = CardServices(RequestWindow, &link->win, &req); + DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); + if(ret) { + req.Size >>= 1; + } else { + DEBUG(2, "Got window of size %dKB", req.Size >> 10); + dev->win_size = req.Size; + break; + } + } while(req.Size >= 0x1000); + + DEBUG(2, "dev->win_size = %d", dev->win_size); + + if(!dev->win_size) { + err("Cant allocate memory window"); + pcmciamtd_release((u_long)link); + return; + } + DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10); + + /* Get write protect status */ + CS_CHECK(GetStatus, link->handle, &status); + DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", + status.CardState, (unsigned long)link->win); + dev->win_base = ioremap(req.Base, req.Size); + if(!dev->win_base) { + err("ioremap(%lu, %u) failed", req.Base, req.Size); + pcmciamtd_release((u_long)link); + return; + } + DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x", + dev, req.Base, dev->win_base, req.Size); + dev->cardsize = 0; + dev->offset = 0; + + dev->pcmcia_map.map_priv_1 = (unsigned long)dev; + dev->pcmcia_map.map_priv_2 = (unsigned long)link->win; + + DEBUG(2, "Getting configuration"); + CS_CHECK(GetConfigurationInfo, link->handle, &t); + DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2); + dev->vpp = (vpp) ? vpp : t.Vpp1; + link->conf.Attributes = 0; + link->conf.Vcc = t.Vcc; + if(setvpp == 2) { + link->conf.Vpp1 = dev->vpp; + link->conf.Vpp2 = dev->vpp; + } else { + link->conf.Vpp1 = 0; + link->conf.Vpp2 = 0; + } + + link->conf.IntType = INT_MEMORY; + link->conf.ConfigBase = t.ConfigBase; + link->conf.Status = t.Status; + link->conf.Pin = t.Pin; + link->conf.Copy = t.Copy; + link->conf.ExtStatus = t.ExtStatus; + link->conf.ConfigIndex = 0; + link->conf.Present = t.Present; + DEBUG(2, "Setting Configuration"); + ret = CardServices(RequestConfiguration, link->handle, &link->conf); + if(ret != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, ret); + } + + link->dev = NULL; + link->state &= ~DEV_CONFIG_PENDING; + + if(mem_type == 1) { + mtd = do_map_probe("map_ram", &dev->pcmcia_map); + } else if(mem_type == 2) { + mtd = do_map_probe("map_rom", &dev->pcmcia_map); + } else { + for(i = 0; i < sizeof(probes) / sizeof(char *); i++) { + DEBUG(1, "Trying %s", probes[i]); + mtd = do_map_probe(probes[i], &dev->pcmcia_map); + if(mtd) + break; + + DEBUG(1, "FAILED: %s", probes[i]); + } + } + + if(!mtd) { + DEBUG(1, "Cant find an MTD"); + pcmciamtd_release((u_long)link); + return; + } + + dev->mtd_info = mtd; + mtd->module = THIS_MODULE; + dev->cardsize = mtd->size; + + if(new_name) { + int size = 0; + char unit = ' '; + /* Since we are using a default name, make it better by adding in the + size */ + if(mtd->size < 1048576) { /* <1MB in size, show size in K */ + size = mtd->size >> 10; + unit = 'K'; + } else { + size = mtd->size >> 20; + unit = 'M'; + } + sprintf(mtd->name, "%d%cB %s", size, unit, "PCMCIA Memory card"); + } + + /* If the memory found is fits completely into the mapped PCMCIA window, + use the faster non-remapping read/write functions */ + if(dev->cardsize <= dev->win_size) { + DEBUG(1, "Using non remapping memory functions"); + + dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base; + dev->pcmcia_map.read8 = pcmcia_read8; + dev->pcmcia_map.read16 = pcmcia_read16; + dev->pcmcia_map.copy_from = pcmcia_copy_from; + dev->pcmcia_map.write8 = pcmcia_write8; + dev->pcmcia_map.write16 = pcmcia_write16; + dev->pcmcia_map.copy_to = pcmcia_copy_to; + } + + MOD_INC_USE_COUNT; + if(add_mtd_device(mtd)) { + dev->mtd_info = NULL; + MOD_DEC_USE_COUNT; + err("Couldnt register MTD device"); + pcmciamtd_release((u_long)link); + return; + } + DEBUG(1, "mtd added @ %p mtd->priv = %p", mtd, mtd->priv); + + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + err("CS Error, exiting"); + pcmciamtd_release((u_long)link); + return; +} + + +/* The card status event handler. Mostly, this schedules other + * stuff to run after an event is received. A CARD_REMOVAL event + * also sets some flags to discourage the driver from trying + * to talk to the card any more. + */ + +static int pcmciamtd_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DEBUG(1, "event=0x%06x", event); + switch (event) { + case CS_EVENT_CARD_REMOVAL: + DEBUG(2, "EVENT_CARD_REMOVAL"); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) + mod_timer(&link->release, jiffies + HZ/20); + break; + case CS_EVENT_CARD_INSERTION: + DEBUG(2, "EVENT_CARD_INSERTION"); + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + pcmciamtd_config(link); + break; + case CS_EVENT_PM_SUSPEND: + DEBUG(2, "EVENT_PM_SUSPEND"); + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + DEBUG(2, "EVENT_RESET_PHYSICAL"); + /* get_lock(link); */ + break; + case CS_EVENT_PM_RESUME: + DEBUG(2, "EVENT_PM_RESUME"); + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + DEBUG(2, "EVENT_CARD_RESET"); + /* free_lock(link); */ + break; + default: + DEBUG(2, "Unknown event %d", event); + } + return 0; +} + + +/* This deletes a driver "instance". The device is de-registered + * with Card Services. If it has been released, all local data + * structures are freed. Otherwise, the structures will be freed + * when the device is released. + */ + +static void pcmciamtd_detach(dev_link_t *link) +{ + int ret; + struct pcmciamtd_dev *dev = NULL; + struct list_head *temp1, *temp2; + + DEBUG(3, "link=0x%p", link); + + /* Find device in list */ + list_for_each_safe(temp1, temp2, &dev_list) { + dev = list_entry(temp1, struct pcmciamtd_dev, list); + if(link == &dev->link) + break; + } + if(link != &dev->link) { + DEBUG(1, "Cant find %p in dev_list", link); + return; + } + + del_timer(&link->release); + + if(!dev) { + DEBUG(3, "dev is NULL"); + return; + } + + if (link->state & DEV_CONFIG) { + //pcmciamtd_release((u_long)link); + DEBUG(3, "DEV_CONFIG set"); + link->state |= DEV_STALE_LINK; + return; + } + + if (link->handle) { + DEBUG(2, "Deregistering with card services"); + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + DEBUG(3, "Freeing dev (%p)", dev); + list_del(&dev->list); + link->priv = NULL; + kfree(dev); +} + + +/* pcmciamtd_attach() creates an "instance" of the driver, allocating + * local data structures for one device. The device is registered + * with Card Services. + */ + +static dev_link_t *pcmciamtd_attach(void) +{ + struct pcmciamtd_dev *dev; + dev_link_t *link; + client_reg_t client_reg; + int ret; + + /* Create new memory card device */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) return NULL; + DEBUG(1, "dev=0x%p", dev); + + memset(dev, 0, sizeof(*dev)); + link = &dev->link; link->priv = dev; + + link->release.function = &pcmciamtd_release; + link->release.data = (u_long)link; + + link->conf.Attributes = 0; + link->conf.IntType = INT_MEMORY; + + list_add(&dev->list, &dev_list); + + /* Register with Card Services */ + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &pcmciamtd_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + DEBUG(2, "Calling RegisterClient"); + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + pcmciamtd_detach(link); + return NULL; + } + + return link; +} + + +static int __init init_pcmciamtd(void) +{ + servinfo_t serv; + + info(DRIVER_DESC " " DRIVER_VERSION); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + err("Card Services release does not match!"); + return -1; + } + + if(buswidth && buswidth != 1 && buswidth != 2) { + info("bad buswidth (%d), using default", buswidth); + buswidth = 2; + } + if(force_size && (force_size < 1 || force_size > 64)) { + info("bad force_size (%d), using default", force_size); + force_size = 0; + } + if(mem_type && mem_type != 1 && mem_type != 2) { + info("bad mem_type (%d), using default", mem_type); + mem_type = 0; + } + register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach); + return 0; +} + + +static void __exit exit_pcmciamtd(void) +{ + struct list_head *temp1, *temp2; + + DEBUG(1, DRIVER_DESC " unloading"); + unregister_pccard_driver(&dev_info); + list_for_each_safe(temp1, temp2, &dev_list) { + dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link; + if (link && (link->state & DEV_CONFIG)) { + pcmciamtd_release((u_long)link); + pcmciamtd_detach(link); + } + } +} + +module_init(init_pcmciamtd); +module_exit(exit_pcmciamtd); diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c --- a/drivers/mtd/maps/sa1100-flash.c Tue Oct 15 20:29:14 2002 +++ b/drivers/mtd/maps/sa1100-flash.c Tue Oct 15 20:29:14 2002 @@ -3,28 +3,35 @@ * * (C) 2000 Nicolas Pitre * - * $Id: sa1100-flash.c,v 1.22 2001/10/02 10:04:52 rmk Exp $ + * $Id: sa1100-flash.c,v 1.28 2002/05/07 13:48:38 abz Exp $ */ #include #include #include +#include #include #include #include #include +#include #include +#include #include +#include +#include #ifndef CONFIG_ARCH_SA1100 #error This is for SA1100 architecture only #endif - -#define WINDOW_ADDR 0xe8000000 +/* + * This isnt complete yet, so... + */ +#define CONFIG_MTD_SA1100_STATICMAP 1 static __u8 sa1100_read8(struct map_info *map, unsigned long ofs) { @@ -66,33 +73,7 @@ memcpy((void *)(map->map_priv_1 + to), from, len); } - -#ifdef CONFIG_SA1100_H3600 - -static void h3600_set_vpp(struct map_info *map, int vpp) -{ - if (vpp) - set_h3600_egpio(EGPIO_H3600_VPP_ON); - else - clr_h3600_egpio(EGPIO_H3600_VPP_ON); -} - -#endif - -#ifdef CONFIG_SA1100_JORNADA720 - -static void jornada720_set_vpp(int vpp) -{ - if (vpp) - PPSR |= 0x80; - else - PPSR &= ~0x80; - PPDR |= 0x80; -} - -#endif - -static struct map_info sa1100_map = { +static struct map_info sa1100_map __initdata = { name: "SA1100 flash", read8: sa1100_read8, read16: sa1100_read16, @@ -102,609 +83,1232 @@ write16: sa1100_write16, write32: sa1100_write32, copy_to: sa1100_copy_to, - - map_priv_1: WINDOW_ADDR, }; +#ifdef CONFIG_MTD_SA1100_STATICMAP /* * Here are partition information for all known SA1100-based devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition * structure. - * - * The *_max_flash_size is the maximum possible mapped flash size which - * is not necessarily the actual flash size. It must correspond to the - * value specified in the mapping definition defined by the - * "struct map_desc *_io_desc" for the corresponding machine. + * + * Please note: + * 1. We no longer support static flash mappings via the machine io_desc + * structure. + * 2. The flash size given should be the largest flash size that can + * be accomodated. + * + * The MTD layer will detect flash chip aliasing and reduce the size of + * the map accordingly. + * + * Please keep these in alphabetical order, and formatted as per existing + * entries. Thanks. */ -#ifdef CONFIG_SA1100_ASSABET +#ifdef CONFIG_SA1100_ADSBITSY +static struct mtd_partition adsbitsy_partitions[] = { + { + name: "bootROM", + size: 0x80000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "zImage", + size: 0x100000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif +#ifdef CONFIG_SA1100_ASSABET /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */ -static unsigned long assabet4_max_flash_size = 0x00400000; static struct mtd_partition assabet4_partitions[] = { - { - name: "bootloader", - size: 0x00020000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00020000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND - } + { + name: "bootloader", + size: 0x00020000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00020000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "jffs", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } }; /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */ -static unsigned long assabet5_max_flash_size = 0x02000000; static struct mtd_partition assabet5_partitions[] = { - { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "jffs", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND - } + { + name: "bootloader", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "jffs", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } }; -#define assabet_max_flash_size assabet5_max_flash_size -#define assabet_partitions assabet5_partitions - +#define assabet_partitions assabet5_partitions #endif -#ifdef CONFIG_SA1100_FLEXANET - -/* Flexanet has two 28F128J3A flash parts in bank 0: */ -static unsigned long flexanet_max_flash_size = 0x02000000; -static struct mtd_partition flexanet_partitions[] = { - { - name: "bootloader", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE - },{ - name: "bootloader params", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "kernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "altkernel", - size: 0x000C0000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "root", - size: 0x00400000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free1", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free2", - size: 0x00300000, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - },{ - name: "free3", - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, - mask_flags: MTD_WRITEABLE - } +#ifdef CONFIG_SA1100_BADGE4 +/* + * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit) + * Eight 4 KiW Parameter Bottom Blocks (64 KiB) + * Sixty-three 32 KiW Main Blocks (4032 Ki b) + */ +static struct mtd_partition badge4_partitions[] = { + { + name: "BLOB boot loader", + offset: 0, + size: 0x0000A000 + }, { + name: "params", + offset: MTDPART_OFS_APPEND, + size: 0x00006000 + }, { + name: "kernel", + offset: MTDPART_OFS_APPEND, + size: 0x00100000 + }, { + name: "root", + offset: MTDPART_OFS_APPEND, + size: MTDPART_SIZ_FULL + } }; - #endif -#ifdef CONFIG_SA1100_HUW_WEBPANEL -static unsigned long huw_webpanel_max_flash_size = 0x01000000; -static struct mtd_partition huw_webpanel_partitions[] = { - { - name: "Loader", - size: 0x00040000, - offset: 0, - },{ - name: "Sector 1", - size: 0x00040000, - offset: MTDPART_OFS_APPEND, - },{ - size: MTDPART_SIZ_FULL, - offset: MTDPART_OFS_APPEND, + +#ifdef CONFIG_SA1100_CERF +#ifdef CONFIG_SA1100_CERF_FLASH_32MB +static struct mtd_partition cerf_partitions[] = { + { + name: "firmware", + size: 0x00040000, + offset: 0, + }, { + name: "params", + size: 0x00040000, + offset: 0x00040000, + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00080000, + }, { + name: "rootdisk", + size: 0x01E80000, + offset: 0x00180000, } }; -#endif /* CONFIG_SA1100_HUW_WEBPANEL */ - - -#ifdef CONFIG_SA1100_H3600 - -static unsigned long h3600_max_flash_size = 0x02000000; -static struct mtd_partition h3600_partitions[] = { +#elif defined CONFIG_SA1100_CERF_FLASH_16MB +static struct mtd_partition cerf_partitions[] = { { - name: "H3600 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "H3600 kernel", - size: 0x00080000, - offset: 0x40000 - },{ - name: "H3600 params", - size: 0x00040000, - offset: 0xC0000 - },{ -#ifdef CONFIG_JFFS2_FS - name: "H3600 root jffs2", - offset: 0x00100000, - size: MTDPART_SIZ_FULL + name: "firmware", + size: 0x00020000, + offset: 0, + }, { + name: "params", + size: 0x00020000, + offset: 0x00020000, + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00040000, + }, { + name: "rootdisk", + size: 0x00EC0000, + offset: 0x00140000, + } +}; +#elif defined CONFIG_SA1100_CERF_FLASH_8MB +# error "Unwritten type definition" #else - name: "H3600 initrd", - size: 0x00100000, - offset: 0x00100000 - },{ - name: "H3600 root cramfs", - size: 0x00300000, - offset: 0x00200000 - },{ - name: "H3600 usr cramfs", - size: 0x00800000, - offset: 0x00500000 - },{ - name: "H3600 usr local", - offset: 0x00d00000, - size: MTDPART_SIZ_FULL +# error "Undefined memory orientation for CERF in sa1100-flash.c" #endif +#endif + +#ifdef CONFIG_SA1100_CONSUS +static struct mtd_partition consus_partitions[] = { + { + name: "Consus boot firmware", + offset: 0, + size: 0x00040000, + mask_flags: MTD_WRITABLE, /* force read-only */ + }, { + name: "Consus kernel", + offset: 0x00040000, + size: 0x00100000, + mask_flags: 0, + }, { + name: "Consus disk", + offset: 0x00140000, + /* The rest (up to 16M) for jffs. We could put 0 and + make it find the size automatically, but right now + i have 32 megs. jffs will use all 32 megs if given + the chance, and this leads to horrible problems + when you try to re-flash the image because blob + won't erase the whole partition. */ + size: 0x01000000 - 0x00140000, + mask_flags: 0, + }, { + /* this disk is a secondary disk, which can be used as + needed, for simplicity, make it the size of the other + consus partition, although realistically it could be + the remainder of the disk (depending on the file + system used) */ + name: "Consus disk2", + offset: 0x01000000, + size: 0x01000000 - 0x00140000, + mask_flags: 0, } }; +#endif +#ifdef CONFIG_SA1100_FLEXANET +/* Flexanet has two 28F128J3A flash parts in bank 0: */ +#define FLEXANET_FLASH_SIZE 0x02000000 +static struct mtd_partition flexanet_partitions[] = { + { + name: "bootloader", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "kernel", + size: 0x000C0000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "altkernel", + size: 0x000C0000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "root", + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free1", + size: 0x00300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free2", + size: 0x00300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + }, { + name: "free3", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, + } +}; #endif + #ifdef CONFIG_SA1100_FREEBIRD -static unsigned long freebird_max_flash_size = 0x02000000; static struct mtd_partition freebird_partitions[] = { #if CONFIG_SA1100_FREEBIRD_NEW - { - name: "firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "kernel", - size: 0x00080000, - offset: 0x40000 - },{ - name: "params", - size: 0x00040000, - offset: 0xC0000 - },{ - name: "initrd", - size: 0x00100000, - offset: 0x00100000 - },{ - name: "root cramfs", - size: 0x00300000, - offset: 0x00200000 - },{ - name: "usr cramfs", - size: 0x00C00000, - offset: 0x00500000 - },{ - name: "local", - offset: 0x01100000, - size: MTDPART_SIZ_FULL + { + name: "firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00080000, + offset: 0x00040000, + }, { + name: "params", + size: 0x00040000, + offset: 0x000C0000, + }, { + name: "initrd", + size: 0x00100000, + offset: 0x00100000, + }, { + name: "root cramfs", + size: 0x00300000, + offset: 0x00200000, + }, { + name: "usr cramfs", + size: 0x00C00000, + offset: 0x00500000, + }, { + name: "local", + size: MTDPART_SIZ_FULL, + offset: 0x01100000, } #else - { offset: 0, size: 0x00040000, }, - { offset: MTDPART_OFS_APPEND, size: 0x000c0000, }, - { offset: MTDPART_OFS_APPEND, size: 0x00400000, }, - { offset: MTDPART_OFS_APPEND, size: MTDPART_SIZ_FULL } + { + size: 0x00040000, + offset: 0, + }, { + size: 0x000c0000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + }, { + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } #endif - }; +}; #endif - -#ifdef CONFIG_SA1100_CERF - -static unsigned long cerf_max_flash_size = 0x01000000; -static struct mtd_partition cerf_partitions[] = { - { offset: 0, size: 0x00800000 }, - { offset: MTDPART_OFS_APPEND, size: 0x00800000 } +#ifdef CONFIG_SA1100_FRODO +/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */ +static struct mtd_partition frodo_partitions[] = +{ + { + name: "bootloader", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE + }, { + name: "bootloader params", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "kernel", + size: 0x00100000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "ramdisk", + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE + }, { + name: "file system", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND + } }; - #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT - -static unsigned long graphicsclient_max_flash_size = 0x01000000; static struct mtd_partition graphicsclient_partitions[] = { - { - name: "zImage", - offset: 0, - size: 0x100000 - }, - { - name: "ramdisk.gz", - offset: MTDPART_OFS_APPEND, - size: 0x300000 - }, - { - name: "User FS", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + { + name: "zImage", + size: 0x100000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, } }; - #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER - -static unsigned long graphicsmaster_max_flash_size = 0x01000000; static struct mtd_partition graphicsmaster_partitions[] = { - { - name: "zImage", - offset: 0, - size: 0x100000 + { + name: "zImage", + size: 0x100000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ }, - { - name: "ramdisk.gz", - offset: MTDPART_OFS_APPEND, - size: 0x300000 + { + name: "ramdisk.gz", + size: 0x300000, + offset: MTDPART_OFS_APPEND, + mask_flags: MTD_WRITEABLE, /* force read-only */ }, - { - name: "User FS", - offset: MTDPART_OFS_APPEND, - size: MTDPART_SIZ_FULL + { + name: "User FS", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, } }; +#endif +#ifdef CONFIG_SA1100_H3XXX +static struct mtd_partition h3xxx_partitions[] = { + { + name: "H3XXX boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { +#ifdef CONFIG_MTD_2PARTS_IPAQ + name: "H3XXX root jffs2", + size: MTDPART_SIZ_FULL, + offset: 0x00040000, +#else + name: "H3XXX kernel", + size: 0x00080000, + offset: 0x00040000, + }, { + name: "H3XXX params", + size: 0x00040000, + offset: 0x000C0000, + }, { +#ifdef CONFIG_JFFS2_FS + name: "H3XXX root jffs2", + size: MTDPART_SIZ_FULL, + offset: 0x00100000, +#else + name: "H3XXX initrd", + size: 0x00100000, + offset: 0x00100000, + }, { + name: "H3XXX root cramfs", + size: 0x00300000, + offset: 0x00200000, + }, { + name: "H3XXX usr cramfs", + size: 0x00800000, + offset: 0x00500000, + }, { + name: "H3XXX usr local", + size: MTDPART_SIZ_FULL, + offset: 0x00d00000, +#endif #endif + } +}; -#ifdef CONFIG_SA1100_PANGOLIN +static void h3xxx_set_vpp(struct map_info *map, int vpp) +{ + assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp); +} +#else +#define h3xxx_set_vpp NULL +#endif -static unsigned long pangolin_max_flash_size = 0x04000000; -static struct mtd_partition pangolin_partitions[] = { - { - name: "boot firmware", - offset: 0x00000000, - size: 0x00080000, - mask_flags: MTD_WRITEABLE, /* force read-only */ - }, - { - name: "kernel", - offset: 0x00080000, - size: 0x00100000, - }, +#ifdef CONFIG_SA1100_HUW_WEBPANEL +static struct mtd_partition huw_webpanel_partitions[] = { { - name: "initrd", - offset: 0x00180000, - size: 0x00280000, - }, + name: "Loader", + size: 0x00040000, + offset: 0, + }, { + name: "Sector 1", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + }, { + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif + +#ifdef CONFIG_SA1100_JORNADA720 +static struct mtd_partition jornada720_partitions[] = { { - name: "initrd-test", - offset: 0x00400000, - size: 0x03C00000, + name: "JORNADA720 boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "JORNADA720 kernel", + size: 0x000c0000, + offset: 0x00040000, + }, { + name: "JORNADA720 params", + size: 0x00040000, + offset: 0x00100000, + }, { + name: "JORNADA720 initrd", + size: 0x00100000, + offset: 0x00140000, + }, { + name: "JORNADA720 root cramfs", + size: 0x00300000, + offset: 0x00240000, + }, { + name: "JORNADA720 usr cramfs", + size: 0x00800000, + offset: 0x00540000, + }, { + name: "JORNADA720 usr local", + size: 0 /* will expand to the end of the flash */ + offset: 0x00d00000, } }; +static void jornada720_set_vpp(int vpp) +{ + if (vpp) + PPSR |= 0x80; + else + PPSR &= ~0x80; + PPDR |= 0x80; +} +#else +#define jornada720_set_vpp NULL +#endif + +#ifdef CONFIG_SA1100_PANGOLIN +static struct mtd_partition pangolin_partitions[] = { + { + name: "boot firmware", + size: 0x00080000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00100000, + offset: 0x00080000, + }, { + name: "initrd", + size: 0x00280000, + offset: 0x00180000, + }, { + name: "initrd-test", + size: 0x03C00000, + offset: 0x00400000, + } +}; #endif -#ifdef CONFIG_SA1100_YOPY +#ifdef CONFIG_SA1100_PT_SYSTEM3 +/* erase size is 0x40000 == 256k partitions have to have this boundary */ +static struct mtd_partition system3_partitions[] = { + { + name: "BLOB", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "config", + size: 0x00040000, + offset: MTDPART_OFS_APPEND, + }, { + name: "kernel", + size: 0x00100000, + offset: MTDPART_OFS_APPEND, + }, { + name: "root", + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif -static unsigned long yopy_max_flash_size = 0x08000000; -static struct mtd_partition yopy_partitions[] = { +#ifdef CONFIG_SA1100_SHANNON +static struct mtd_partition shannon_partitions[] = { { - name: "boot firmware", - offset: 0x00000000, - size: 0x00040000, - mask_flags: MTD_WRITEABLE, /* force read-only */ + name: "BLOB boot loader", + offset: 0, + size: 0x20000 }, { name: "kernel", - offset: 0x00080000, - size: 0x00080000, + offset: MTDPART_OFS_APPEND, + size: 0xe0000 }, - { + { name: "initrd", - offset: 0x00100000, - size: 0x00300000, - }, - { - name: "root", - offset: 0x00400000, - size: 0x01000000, - }, + offset: MTDPART_OFS_APPEND, + size: MTDPART_SIZ_FULL + } }; #endif -#ifdef CONFIG_SA1100_JORNADA720 - -static unsigned long jornada720_max_flash_size = 0x02000000; -static struct mtd_partition jornada720_partitions[] = { +#ifdef CONFIG_SA1100_SHERMAN +static struct mtd_partition sherman_partitions[] = { { - name: "JORNADA720 boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "JORNADA720 kernel", - size: 0x000c0000, - offset: 0x40000 - },{ - name: "JORNADA720 params", - size: 0x00040000, - offset: 0x100000 - },{ - name: "JORNADA720 initrd", - size: 0x00100000, - offset: 0x00140000 - },{ - name: "JORNADA720 root cramfs", - size: 0x00300000, - offset: 0x00240000 - },{ - name: "JORNADA720 usr cramfs", - size: 0x00800000, - offset: 0x00540000 - },{ - name: "JORNADA720 usr local", - offset: 0x00d00000, - size: 0 /* will expand to the end of the flash */ + size: 0x50000, + offset: 0, + }, { + size: 0x70000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0x600000, + offset: MTDPART_OFS_APPEND, + }, { + size: 0xA0000, + offset: MTDPART_OFS_APPEND, } }; #endif -#ifdef CONFIG_SA1100_SHERMAN - -static unsigned long sherman_max_flash_size = 0x02000000; -static struct mtd_partition sherman_partitions[] = { - { offset: 0, size: 0x50000 }, - { offset: MTDPART_OFS_APPEND, size: 0x70000 }, - { offset: MTDPART_OFS_APPEND, size: 0x600000 }, - { offset: MTDPART_OFS_APPEND, size: 0xA0000 } -}; - +#ifdef CONFIG_SA1100_SIMPAD +static struct mtd_partition simpad_partitions[] = { + { + name: "SIMpad boot firmware", + size: 0x00080000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "SIMpad kernel", + size: 0x00100000, + offset: 0x00080000, + }, { +#ifdef CONFIG_JFFS2_FS + name: "SIMpad root jffs2", + size: MTDPART_SIZ_FULL, + offset: 0x00180000, +#else + name: "SIMpad initrd", + size: 0x00300000, + offset: 0x00180000, + }, { + name: "SIMpad root cramfs", + size: 0x00300000, + offset: 0x00480000, + }, { + name: "SIMpad usr cramfs", + size: 0x005c0000, + offset: 0x00780000, + }, { + name: "SIMpad usr local", + size: MTDPART_SIZ_FULL, + offset: 0x00d40000, #endif + } +}; +#endif /* CONFIG_SA1100_SIMPAD */ #ifdef CONFIG_SA1100_STORK - -static unsigned long stork_max_flash_size = 0x02000000; static struct mtd_partition stork_partitions[] = { { - name: "STORK boot firmware", - size: 0x00040000, - offset: 0, - mask_flags: MTD_WRITEABLE /* force read-only */ - },{ - name: "STORK params", - size: 0x00040000, - offset: 0x40000 - },{ - name: "STORK kernel", - size: 0x00100000, - offset: 0x80000 - },{ + name: "STORK boot firmware", + size: 0x00040000, + offset: 0, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "STORK params", + size: 0x00040000, + offset: 0x00040000, + }, { + name: "STORK kernel", + size: 0x00100000, + offset: 0x00080000, + }, { #ifdef CONFIG_JFFS2_FS - name: "STORK root jffs2", - offset: 0x00180000, - size: MTDPART_SIZ_FULL + name: "STORK root jffs2", + offset: 0x00180000, + size: MTDPART_SIZ_FULL, #else - name: "STORK initrd", - size: 0x00100000, - offset: 0x00180000 - },{ - name: "STORK root cramfs", - size: 0x00300000, - offset: 0x00280000 - },{ - name: "STORK usr cramfs", - size: 0x00800000, - offset: 0x00580000 - },{ - name: "STORK usr local", - offset: 0x00d80000, - size: MTDPART_SIZ_FULL + name: "STORK initrd", + size: 0x00100000, + offset: 0x00180000, + }, { + name: "STORK root cramfs", + size: 0x00300000, + offset: 0x00280000, + }, { + name: "STORK usr cramfs", + size: 0x00800000, + offset: 0x00580000, + }, { + name: "STORK usr local", + offset: 0x00d80000, + size: MTDPART_SIZ_FULL, #endif } }; - #endif -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - - -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts); +#ifdef CONFIG_SA1100_TRIZEPS +static struct mtd_partition trizeps_partitions[] = { + { + name: "Bootloader & the kernel", + size: 0x00200000, + offset: 0, + }, { + name: "Data", + size: 0x00400000, + offset: MTDPART_OFS_APPEND, + }, { + size: MTDPART_SIZ_FULL, + offset: MTDPART_OFS_APPEND, + } +}; +#endif -static struct mtd_partition *parsed_parts; -static struct mtd_info *mymtd; +#ifdef CONFIG_SA1100_YOPY +static struct mtd_partition yopy_partitions[] = { + { + name: "boot firmware", + size: 0x00040000, + offset: 0x00000000, + mask_flags: MTD_WRITEABLE, /* force read-only */ + }, { + name: "kernel", + size: 0x00080000, + offset: 0x00080000, + }, { + name: "initrd", + size: 0x00300000, + offset: 0x00100000, + }, { + name: "root", + size: 0x01000000, + offset: 0x00400000, + } +}; +#endif -int __init sa1100_mtd_init(void) +static int __init sa1100_static_partitions(struct mtd_partition **parts) { - struct mtd_partition *parts; int nb_parts = 0; - int parsed_nr_parts = 0; - char *part_type; - - /* Default flash buswidth */ - sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4; - /* - * Static partition definition selection - */ - part_type = "static"; +#ifdef CONFIG_SA1100_ADSBITSY + if (machine_is_adsbitsy()) { + *parts = adsbitsy_partitions; + nb_parts = ARRAY_SIZE(adsbitsy_partitions); + } +#endif #ifdef CONFIG_SA1100_ASSABET if (machine_is_assabet()) { - parts = assabet_partitions; - nb_parts = NB_OF(assabet_partitions); - sa1100_map.size = assabet_max_flash_size; + *parts = assabet_partitions; + nb_parts = ARRAY_SIZE(assabet_partitions); } #endif - -#ifdef CONFIG_SA1100_HUW_WEBPANEL - if (machine_is_huw_webpanel()) { - parts = huw_webpanel_partitions; - nb_parts = NB_OF(huw_webpanel_partitions); - sa1100_map.size = huw_webpanel_max_flash_size; +#ifdef CONFIG_SA1100_BADGE4 + if (machine_is_badge4()) { + *parts = badge4_partitions; + nb_parts = ARRAY_SIZE(badge4_partitions); } #endif - -#ifdef CONFIG_SA1100_H3600 - if (machine_is_h3600()) { - parts = h3600_partitions; - nb_parts = NB_OF(h3600_partitions); - sa1100_map.size = h3600_max_flash_size; - sa1100_map.set_vpp = h3600_set_vpp; +#ifdef CONFIG_SA1100_CERF + if (machine_is_cerf()) { + *parts = cerf_partitions; + nb_parts = ARRAY_SIZE(cerf_partitions); + } +#endif +#ifdef CONFIG_SA1100_CONSUS + if (machine_is_consus()) { + *parts = consus_partitions; + nb_parts = ARRAY_SIZE(consus_partitions); + } +#endif +#ifdef CONFIG_SA1100_FLEXANET + if (machine_is_flexanet()) { + *parts = flexanet_partitions; + nb_parts = ARRAY_SIZE(flexanet_partitions); } #endif #ifdef CONFIG_SA1100_FREEBIRD if (machine_is_freebird()) { - parts = freebird_partitions; - nb_parts = NB_OF(freebird_partitions); - sa1100_map.size = freebird_max_flash_size; + *parts = freebird_partitions; + nb_parts = ARRAY_SIZE(freebird_partitions); } #endif -#ifdef CONFIG_SA1100_CERF - if (machine_is_cerf()) { - parts = cerf_partitions; - nb_parts = NB_OF(cerf_partitions); - sa1100_map.size = cerf_max_flash_size; +#ifdef CONFIG_SA1100_FRODO + if (machine_is_frodo()) { + *parts = frodo_partitions; + nb_parts = ARRAY_SIZE(frodo_partitions); } -#endif +#endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT if (machine_is_graphicsclient()) { - parts = graphicsclient_partitions; - nb_parts = NB_OF(graphicsclient_partitions); - sa1100_map.size = graphicsclient_max_flash_size; - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; + *parts = graphicsclient_partitions; + nb_parts = ARRAY_SIZE(graphicsclient_partitions); } #endif #ifdef CONFIG_SA1100_GRAPHICSMASTER if (machine_is_graphicsmaster()) { - parts = graphicsmaster_partitions; - nb_parts = NB_OF(graphicsmaster_partitions); - sa1100_map.size = graphicsmaster_max_flash_size; - sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; + *parts = graphicsmaster_partitions; + nb_parts = ARRAY_SIZE(graphicsmaster_partitions); } #endif -#ifdef CONFIG_SA1100_PANGOLIN - if (machine_is_pangolin()) { - parts = pangolin_partitions; - nb_parts = NB_OF(pangolin_partitions); - sa1100_map.size = pangolin_max_flash_size; +#ifdef CONFIG_SA1100_H3XXX + if (machine_is_h3xxx()) { + *parts = h3xxx_partitions; + nb_parts = ARRAY_SIZE(h3xxx_partitions); + } +#endif +#ifdef CONFIG_SA1100_HUW_WEBPANEL + if (machine_is_huw_webpanel()) { + *parts = huw_webpanel_partitions; + nb_parts = ARRAY_SIZE(huw_webpanel_partitions); } #endif #ifdef CONFIG_SA1100_JORNADA720 if (machine_is_jornada720()) { - parts = jornada720_partitions; - nb_parts = NB_OF(jornada720_partitions); - sa1100_map.size = jornada720_max_flash_size; - sa1100_map.set_vpp = jornada720_set_vpp; + *parts = jornada720_partitions; + nb_parts = ARRAY_SIZE(jornada720_partitions); } #endif -#ifdef CONFIG_SA1100_YOPY - if (machine_is_yopy()) { - parts = yopy_partitions; - nb_parts = NB_OF(yopy_partitions); - sa1100_map.size = yopy_max_flash_size; +#ifdef CONFIG_SA1100_PANGOLIN + if (machine_is_pangolin()) { + *parts = pangolin_partitions; + nb_parts = ARRAY_SIZE(pangolin_partitions); + } +#endif +#ifdef CONFIG_SA1100_PT_SYSTEM3 + if (machine_is_pt_system3()) { + *parts = system3_partitions; + nb_parts = ARRAY_SIZE(system3_partitions); + } +#endif +#ifdef CONFIG_SA1100_SHANNON + if (machine_is_shannon()) { + *parts = shannon_partitions; + nb_parts = ARRAY_SIZE(shannon_partitions); } #endif #ifdef CONFIG_SA1100_SHERMAN if (machine_is_sherman()) { - parts = sherman_partitions; - nb_parts = NB_OF(sherman_partitions); - sa1100_map.size = sherman_max_flash_size; + *parts = sherman_partitions; + nb_parts = ARRAY_SIZE(sherman_partitions); } #endif -#ifdef CONFIG_SA1100_FLEXANET - if (machine_is_flexanet()) { - parts = flexanet_partitions; - nb_parts = NB_OF(flexanet_partitions); - sa1100_map.size = flexanet_max_flash_size; +#ifdef CONFIG_SA1100_SIMPAD + if (machine_is_simpad()) { + *parts = simpad_partitions; + nb_parts = ARRAY_SIZE(simpad_partitions); } #endif #ifdef CONFIG_SA1100_STORK if (machine_is_stork()) { - parts = stork_partitions; - nb_parts = NB_OF(stork_partitions); - sa1100_map.size = stork_max_flash_size; + *parts = stork_partitions; + nb_parts = ARRAY_SIZE(stork_partitions); + } +#endif +#ifdef CONFIG_SA1100_TRIZEPS + if (machine_is_trizeps()) { + *parts = trizeps_partitions; + nb_parts = ARRAY_SIZE(trizeps_parititons); + } +#endif +#ifdef CONFIG_SA1100_YOPY + if (machine_is_yopy()) { + *parts = yopy_partitions; + nb_parts = ARRAY_SIZE(yopy_partitions); } #endif + return nb_parts; +} +#endif + +struct sa_info { + unsigned long base; + unsigned long size; + int width; + void *vbase; + struct map_info *map; + struct mtd_info *mtd; + struct resource *res; +}; + +#define NR_SUBMTD 4 + +static struct sa_info info[NR_SUBMTD]; + +static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd) +{ + struct mtd_info *subdev[nr]; + struct map_info *maps; + int i, found = 0, ret = 0; + /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. + * Allocate the map_info structs in one go. */ - printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8); - mymtd = do_map_probe("cfi_probe", &sa1100_map); - if (!mymtd) - return -ENXIO; - mymtd->module = THIS_MODULE; + maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); + if (!maps) + return -ENOMEM; /* - * Dynamic partition selection stuff (might override the static ones) + * Claim and then map the memory regions. */ -#ifdef CONFIG_MTD_REDBOOT_PARTS - if (parsed_nr_parts == 0) { - int ret = parse_redboot_partitions(mymtd, &parsed_parts); - - if (ret > 0) { - part_type = "RedBoot"; - parsed_nr_parts = ret; + for (i = 0; i < nr; i++) { + if (sa[i].base == (unsigned long)-1) + break; + + sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash"); + if (!sa[i].res) { + ret = -EBUSY; + break; + } + + sa[i].map = maps + i; + memcpy(sa[i].map, &sa1100_map, sizeof(struct map_info)); + + sa[i].vbase = ioremap(sa[i].base, sa[i].size); + if (!sa[i].vbase) { + ret = -ENOMEM; + break; + } + + sa[i].map->map_priv_1 = (unsigned long)sa[i].vbase; + sa[i].map->buswidth = sa[i].width; + sa[i].map->size = sa[i].size; + + /* + * Now let's probe for the actual flash. Do it here since + * specific machine settings might have been set above. + */ + sa[i].mtd = do_map_probe("cfi_probe", sa[i].map); + if (sa[i].mtd == NULL) { + ret = -ENXIO; + break; } + sa[i].mtd->module = THIS_MODULE; + subdev[i] = sa[i].mtd; + + printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, " + "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20, + sa[i].width * 8); + found += 1; + } + + /* + * ENXIO is special. It means we didn't find a chip when + * we probed. We need to tear down the mapping, free the + * resource and mark it as such. + */ + if (ret == -ENXIO) { + iounmap(sa[i].vbase); + sa[i].vbase = NULL; + release_resource(sa[i].res); + sa[i].res = NULL; } + + /* + * If we found one device, don't bother with concat support. + * If we found multiple devices, use concat if we have it + * available, otherwise fail. + */ + if (ret == 0 || ret == -ENXIO) { + if (found == 1) { + *rmtd = subdev[0]; + ret = 0; + } else if (found > 1) { + /* + * We detected multiple devices. Concatenate + * them together. + */ +#ifdef CONFIG_MTD_CONCAT + *rmtd = mtd_concat_create(subdev, found, + "sa1100 flash"); + if (*rmtd == NULL) + ret = -ENXIO; +#else + printk(KERN_ERR "SA1100 flash: multiple devices " + "found but MTD concat support disabled.\n"); + ret = -ENXIO; #endif -#ifdef CONFIG_MTD_BOOTLDR_PARTS - if (parsed_nr_parts == 0) { - int ret = parse_bootldr_partitions(mymtd, &parsed_parts); - if (ret > 0) { - part_type = "Compaq bootldr"; - parsed_nr_parts = ret; } } -#endif - if (parsed_nr_parts > 0) { - parts = parsed_parts; - nb_parts = parsed_nr_parts; + /* + * If we failed, clean up. + */ + if (ret) { + do { + if (sa[i].mtd) + map_destroy(sa[i].mtd); + if (sa[i].vbase) + iounmap(sa[i].vbase); + if (sa[i].res) + release_resource(sa[i].res); + } while (i--); + + kfree(maps); + } + + return ret; +} + +static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd) +{ + int i; + + del_mtd_partitions(mtd); + + if (mtd != sa[0].mtd) + mtd_concat_destroy(mtd); + + for (i = NR_SUBMTD; i >= 0; i--) { + if (sa[i].mtd) + map_destroy(sa[i].mtd); + if (sa[i].vbase) + iounmap(sa[i].vbase); + if (sa[i].res) + release_resource(sa[i].res); + } + kfree(sa[0].map); +} + +static int __init sa1100_locate_flash(void) +{ + int i, nr = -ENODEV; + + if (machine_is_adsbitsy()) { + info[0].base = SA1100_CS1_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_assabet()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + info[1].base = SA1100_CS1_PHYS; /* neponset */ + info[1].size = SZ_32M; + nr = 2; + } + if (machine_is_badge4()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_4M; + nr = 1; + } + if (machine_is_cerf()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_consus()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_flexanet()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_freebird()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_frodo()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_graphicsclient()) { + info[0].base = SA1100_CS1_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_graphicsmaster()) { + info[0].base = SA1100_CS1_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_h3xxx()) { + sa1100_map.set_vpp = h3xxx_set_vpp; + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_huw_webpanel()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_itsy()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_jornada720()) { + sa1100_map.set_vpp = jornada720_set_vpp; + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_nanoengine()) { + info[0].base = SA1100_CS0_PHYS; + info[1].size = SZ_32M; + nr = 1; + } + if (machine_is_pangolin()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_64M; + nr = 1; + } + if (machine_is_pfs168()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_pleb()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_4M; + info[1].base = SA1100_CS1_PHYS; + info[1].size = SZ_4M; + nr = 2; + } + if (machine_is_pt_system3()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_shannon()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_4M; + nr = 1; + } + if (machine_is_sherman()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_simpad()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_stork()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_32M; + nr = 1; + } + if (machine_is_trizeps()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_16M; + nr = 1; + } + if (machine_is_victor()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_2M; + nr = 1; + } + if (machine_is_yopy()) { + info[0].base = SA1100_CS0_PHYS; + info[0].size = SZ_64M; + info[1].base = SA1100_CS1_PHYS; + info[1].size = SZ_64M; + nr = 2; + } + + if (nr < 0) + return nr; + + /* + * Retrieve the buswidth from the MSC registers. + * We currently only implement CS0 and CS1 here. + */ + for (i = 0; i < nr; i++) { + switch (info[i].base) { + default: + printk(KERN_WARNING "SA1100 flash: unknown base address " + "0x%08lx, assuming CS0\n", info[i].base); + case SA1100_CS0_PHYS: + info[i].width = (MSC0 & MSC_RBW) ? 2 : 4; + break; + + case SA1100_CS1_PHYS: + info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4; + break; + } } - if (nb_parts == 0) { - printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n"); - add_mtd_device(mymtd); + return nr; +} + +extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); +extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); + +static struct mtd_partition *parsed_parts; + +static void __init sa1100_locate_partitions(struct mtd_info *mtd) +{ + const char *part_type = NULL; + int nr_parts = 0; + + do { + /* + * Partition selection stuff. + */ +#ifdef CONFIG_MTD_CMDLINE_PARTS + nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "sa1100"); + if (nr_parts > 0) { + part_type = "command line"; + break; + } +#endif +#ifdef CONFIG_MTD_REDBOOT_PARTS + nr_parts = parse_redboot_partitions(mtd, &parsed_parts); + if (nr_parts > 0) { + part_type = "RedBoot"; + break; + } +#endif +#ifdef CONFIG_MTD_SA1100_STATICMAP + nr_parts = sa1100_static_partitions(&parsed_parts); + if (nr_parts > 0) { + part_type = "static"; + break; + } +#endif + } while (0); + + if (nr_parts == 0) { + printk(KERN_NOTICE "SA1100 flash: no partition info " + "available, registering whole flash\n"); + add_mtd_device(mtd); } else { - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - add_mtd_partitions(mymtd, parts, nb_parts); + printk(KERN_NOTICE "SA1100 flash: using %s partition " + "definition\n", part_type); + add_mtd_partitions(mtd, parsed_parts, nr_parts); } - return 0; + + /* Always succeeds. */ +} + +static void __exit sa1100_destroy_partitions(void) +{ + if (parsed_parts) + kfree(parsed_parts); +} + +static struct mtd_info *mymtd; + +static int __init sa1100_mtd_init(void) +{ + int ret; + int nr; + + nr = sa1100_locate_flash(); + if (nr < 0) + return nr; + + ret = sa1100_setup_mtd(info, nr, &mymtd); + if (ret == 0) + sa1100_locate_partitions(mymtd); + + return ret; } static void __exit sa1100_mtd_cleanup(void) { - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - if (parsed_parts) - kfree(parsed_parts); - } + sa1100_destroy_mtd(info, mymtd); + sa1100_destroy_partitions(); } module_init(sa1100_mtd_init); diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c --- a/drivers/mtd/mtdblock.c Tue Oct 15 20:29:16 2002 +++ b/drivers/mtd/mtdblock.c Tue Oct 15 20:29:16 2002 @@ -295,7 +295,7 @@ spin_unlock(&mtdblks_lock); mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); - disk = alloc_disk(); + disk = alloc_disk(1); if (!mtdblk || !disk) goto Enomem; memset(mtdblk, 0, sizeof(*mtdblk)); @@ -313,7 +313,6 @@ } disk->major = MAJOR_NR; disk->first_minor = dev; - disk->minor_shift = 0; disk->fops = &mtd_fops; sprintf(disk->disk_name, "mtd%d", dev); mtdblk->disk = disk; @@ -518,8 +517,6 @@ switch (cmd) { case BLKFLSBUF: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; fsync_bdev(inode->i_bdev); invalidate_bdev(inode->i_bdev, 0); down(&mtdblk->cache_sem); diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c --- a/drivers/mtd/mtdblock_ro.c Tue Oct 15 20:29:17 2002 +++ b/drivers/mtd/mtdblock_ro.c Tue Oct 15 20:29:17 2002 @@ -15,6 +15,8 @@ #include #include +#include +#include #define LOCAL_END_REQUEST #define MAJOR_NR MTD_BLOCK_MAJOR @@ -47,7 +49,7 @@ return -EINVAL; } - set_capacit(disk, mtd->size>>9); + set_capacity(disk, mtd->size>>9); add_disk(disk); DEBUG(1, "ok\n"); @@ -119,7 +121,7 @@ mtd = __get_mtd_device(NULL, minor(current_request->rq_dev)); if (!mtd) { - printk("MTD device %d doesn't appear to exist any more\n", DEVICE_NR(CURRENT->rq_dev)); + printk("MTD device %s doesn't appear to exist any more\n", kdevname(DEVICE_NR(CURRENT->rq_dev))); mtdblock_end_request(current_request, 0); } @@ -199,8 +201,6 @@ if (!mtd || cmd != BLKFLSBUF) return -EINVAL; - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; fsync_bdev(inode->i_bdev); invalidate_bdev(inode->i_bdev, 0); if (mtd->sync) @@ -222,7 +222,7 @@ int i; for (i = 0; i < MAX_MTD_DEVICES; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); if (!disk) goto out; disk->major = MAJOR_NR; diff -Nru a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/mtdconcat.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,675 @@ +/* + * MTD device concatenation layer + * + * (C) 2002 Robert Kaiser + * + * This code is GPL + * + * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $ + */ + +#include +#include +#include +#include + +#include +#include + +/* + * Our storage structure: + * Subdev points to an array of pointers to struct mtd_info objects + * which is allocated along with this structure + * + */ +struct mtd_concat { + struct mtd_info mtd; + int num_subdev; + struct mtd_info **subdev; +}; + +/* + * how to calculate the size required for the above structure, + * including the pointer array subdev points to: + */ +#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \ + ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *))) + + +/* + * Given a pointer to the MTD object in the mtd_concat structure, + * we can retrieve the pointer to that structure with this macro. + */ +#define CONCAT(x) ((struct mtd_concat *)(x)) + + +/* + * MTD methods which look up the relevant subdevice, translate the + * effective address and pass through to the subdevice. + */ + +static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) + { + size = 0; + from -= subdev->size; + } + else + { + if (from + len > subdev->size) + size = subdev->size - from; + else + size = len; + + err = subdev->read(subdev, from, size, &retsize, buf); + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + from = 0; + } + } + return err; +} + +static int concat_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) + { + size = 0; + to -= subdev->size; + } + else + { + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else + err = subdev->write(subdev, to, size, &retsize, buf); + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; + } + } + return err; +} + +static void concat_erase_callback (struct erase_info *instr) +{ + wake_up((wait_queue_head_t *)instr->priv); +} + +static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) +{ + int err; + wait_queue_head_t waitq; + DECLARE_WAITQUEUE(wait, current); + + /* + * This code was stol^H^H^H^Hinspired by mtdchar.c + */ + init_waitqueue_head(&waitq); + + erase->mtd = mtd; + erase->callback = concat_erase_callback; + erase->priv = (unsigned long)&waitq; + + /* + * FIXME: Allow INTERRUPTIBLE. Which means + * not having the wait_queue head on the stack. + */ + err = mtd->erase(mtd, erase); + if (!err) + { + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&waitq, &wait); + if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED) + schedule(); + remove_wait_queue(&waitq, &wait); + set_current_state(TASK_RUNNING); + + err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0; + } + return err; +} + +static int concat_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + struct mtd_concat *concat = CONCAT(mtd); + struct mtd_info *subdev; + int i, err; + u_int32_t length; + struct erase_info *erase; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + if(instr->addr > concat->mtd.size) + return -EINVAL; + + if(instr->len + instr->addr > concat->mtd.size) + return -EINVAL; + + /* + * Check for proper erase block alignment of the to-be-erased area. + * It is easier to do this based on the super device's erase + * region info rather than looking at each particular sub-device + * in turn. + */ + if (!concat->mtd.numeraseregions) + { /* the easy case: device has uniform erase block size */ + if(instr->addr & (concat->mtd.erasesize - 1)) + return -EINVAL; + if(instr->len & (concat->mtd.erasesize - 1)) + return -EINVAL; + } + else + { /* device has variable erase size */ + struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions; + + /* + * Find the erase region where the to-be-erased area begins: + */ + for(i = 0; i < concat->mtd.numeraseregions && + instr->addr >= erase_regions[i].offset; i++) + ; + --i; + + /* + * Now erase_regions[i] is the region in which the + * to-be-erased area begins. Verify that the starting + * offset is aligned to this region's erase size: + */ + if (instr->addr & (erase_regions[i].erasesize-1)) + return -EINVAL; + + /* + * now find the erase region where the to-be-erased area ends: + */ + for(; i < concat->mtd.numeraseregions && + (instr->addr + instr->len) >= erase_regions[i].offset ; ++i) + ; + --i; + /* + * check if the ending offset is aligned to this region's erase size + */ + if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1)) + return -EINVAL; + } + + /* make a local copy of instr to avoid modifying the caller's struct */ + erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL); + + if (!erase) + return -ENOMEM; + + *erase = *instr; + length = instr->len; + + /* + * find the subdevice where the to-be-erased area begins, adjust + * starting offset to be relative to the subdevice start + */ + for(i = 0; i < concat->num_subdev; i++) + { + subdev = concat->subdev[i]; + if(subdev->size <= erase->addr) + erase->addr -= subdev->size; + else + break; + } + if(i >= concat->num_subdev) /* must never happen since size */ + BUG(); /* limit has been verified above */ + + /* now do the erase: */ + err = 0; + for(;length > 0; i++) /* loop for all subevices affected by this request */ + { + subdev = concat->subdev[i]; /* get current subdevice */ + + /* limit length to subdevice's size: */ + if(erase->addr + length > subdev->size) + erase->len = subdev->size - erase->addr; + else + erase->len = length; + + if (!(subdev->flags & MTD_WRITEABLE)) + { + err = -EROFS; + break; + } + length -= erase->len; + if ((err = concat_dev_erase(subdev, erase))) + { + if(err == -EINVAL) /* sanity check: must never happen since */ + BUG(); /* block alignment has been checked above */ + break; + } + /* + * erase->addr specifies the offset of the area to be + * erased *within the current subdevice*. It can be + * non-zero only the first time through this loop, i.e. + * for the first subdevice where blocks need to be erased. + * All the following erases must begin at the start of the + * current subdevice, i.e. at offset zero. + */ + erase->addr = 0; + } + kfree(erase); + if (err) + return err; + + instr->state = MTD_ERASE_DONE; + if (instr->callback) + instr->callback(instr); + return 0; +} + +static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = -EINVAL; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + + if (ofs >= subdev->size) + { + size = 0; + ofs -= subdev->size; + } + else + { + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = subdev->lock(subdev, ofs, size); + + if(err) + break; + + len -= size; + if(len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + } + return err; +} + +static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, err = 0; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size; + + if (ofs >= subdev->size) + { + size = 0; + ofs -= subdev->size; + } + else + { + if (ofs + len > subdev->size) + size = subdev->size - ofs; + else + size = len; + + err = subdev->unlock(subdev, ofs, size); + + if(err) + break; + + len -= size; + if(len == 0) + break; + + err = -EINVAL; + ofs = 0; + } + } + return err; +} + +static void concat_sync(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + subdev->sync(subdev); + } +} + +static int concat_suspend(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i, rc = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + if((rc = subdev->suspend(subdev)) < 0) + return rc; + } + return rc; +} + +static void concat_resume(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + int i; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + subdev->resume(subdev); + } +} + +/* + * This function constructs a virtual MTD device by concatenating + * num_devs MTD devices. A pointer to the new device object is + * stored to *new_dev upon success. This function does _not_ + * register any devices: this is the caller's responsibility. + */ +struct mtd_info *mtd_concat_create( + struct mtd_info *subdev[], /* subdevices to concatenate */ + int num_devs, /* number of subdevices */ + char *name) /* name for the new device */ +{ + int i; + size_t size; + struct mtd_concat *concat; + u_int32_t max_erasesize, curr_erasesize; + int num_erase_region; + + printk(KERN_NOTICE "Concatenating MTD devices:\n"); + for(i = 0; i < num_devs; i++) + printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name); + printk(KERN_NOTICE "into device \"%s\"\n", name); + + /* allocate the device structure */ + size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); + concat = kmalloc (size, GFP_KERNEL); + if(!concat) + { + printk ("memory allocation error while creating concatenated device \"%s\"\n", + name); + return NULL; + } + memset(concat, 0, size); + concat->subdev = (struct mtd_info **)(concat + 1); + + /* + * Set up the new "super" device's MTD object structure, check for + * incompatibilites between the subdevices. + */ + concat->mtd.type = subdev[0]->type; + concat->mtd.flags = subdev[0]->flags; + concat->mtd.size = subdev[0]->size; + concat->mtd.erasesize = subdev[0]->erasesize; + concat->mtd.oobblock = subdev[0]->oobblock; + concat->mtd.oobsize = subdev[0]->oobsize; + concat->mtd.ecctype = subdev[0]->ecctype; + concat->mtd.eccsize = subdev[0]->eccsize; + + concat->subdev[0] = subdev[0]; + + for(i = 1; i < num_devs; i++) + { + if(concat->mtd.type != subdev[i]->type) + { + kfree(concat); + printk ("Incompatible device type on \"%s\"\n", subdev[i]->name); + return NULL; + } + if(concat->mtd.flags != subdev[i]->flags) + { /* + * Expect all flags except MTD_WRITEABLE to be equal on + * all subdevices. + */ + if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE) + { + kfree(concat); + printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name); + return NULL; + } + else /* if writeable attribute differs, make super device writeable */ + concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE; + } + concat->mtd.size += subdev[i]->size; + if(concat->mtd.oobblock != subdev[i]->oobblock || + concat->mtd.oobsize != subdev[i]->oobsize || + concat->mtd.ecctype != subdev[i]->ecctype || + concat->mtd.eccsize != subdev[i]->eccsize) + { + kfree(concat); + printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); + return NULL; + } + concat->subdev[i] = subdev[i]; + + } + + concat->num_subdev = num_devs; + concat->mtd.name = name; + + /* + * NOTE: for now, we do not provide any readv()/writev() methods + * because they are messy to implement and they are not + * used to a great extent anyway. + */ + concat->mtd.erase = concat_erase; + concat->mtd.read = concat_read; + concat->mtd.write = concat_write; + concat->mtd.sync = concat_sync; + concat->mtd.lock = concat_lock; + concat->mtd.unlock = concat_unlock; + concat->mtd.suspend = concat_suspend; + concat->mtd.resume = concat_resume; + + + /* + * Combine the erase block size info of the subdevices: + * + * first, walk the map of the new device and see how + * many changes in erase size we have + */ + max_erasesize = curr_erasesize = subdev[0]->erasesize; + num_erase_region = 1; + for(i = 0; i < num_devs; i++) + { + if(subdev[i]->numeraseregions == 0) + { /* current subdevice has uniform erase size */ + if(subdev[i]->erasesize != curr_erasesize) + { /* if it differs from the last subdevice's erase size, count it */ + ++num_erase_region; + curr_erasesize = subdev[i]->erasesize; + if(curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + else + { /* current subdevice has variable erase size */ + int j; + for(j = 0; j < subdev[i]->numeraseregions; j++) + { /* walk the list of erase regions, count any changes */ + if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) + { + ++num_erase_region; + curr_erasesize = subdev[i]->eraseregions[j].erasesize; + if(curr_erasesize > max_erasesize) + max_erasesize = curr_erasesize; + } + } + } + } + + if(num_erase_region == 1) + { /* + * All subdevices have the same uniform erase size. + * This is easy: + */ + concat->mtd.erasesize = curr_erasesize; + concat->mtd.numeraseregions = 0; + } + else + { /* + * erase block size varies across the subdevices: allocate + * space to store the data describing the variable erase regions + */ + struct mtd_erase_region_info *erase_region_p; + u_int32_t begin, position; + + concat->mtd.erasesize = max_erasesize; + concat->mtd.numeraseregions = num_erase_region; + concat->mtd.eraseregions = erase_region_p = kmalloc ( + num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL); + if(!erase_region_p) + { + kfree(concat); + printk ("memory allocation error while creating erase region list" + " for device \"%s\"\n", name); + return NULL; + } + + /* + * walk the map of the new device once more and fill in + * in erase region info: + */ + curr_erasesize = subdev[0]->erasesize; + begin = position = 0; + for(i = 0; i < num_devs; i++) + { + if(subdev[i]->numeraseregions == 0) + { /* current subdevice has uniform erase size */ + if(subdev[i]->erasesize != curr_erasesize) + { /* + * fill in an mtd_erase_region_info structure for the area + * we have walked so far: + */ + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + begin = position; + + curr_erasesize = subdev[i]->erasesize; + ++erase_region_p; + } + position += subdev[i]->size; + } + else + { /* current subdevice has variable erase size */ + int j; + for(j = 0; j < subdev[i]->numeraseregions; j++) + { /* walk the list of erase regions, count any changes */ + if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) + { + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + begin = position; + + curr_erasesize = subdev[i]->eraseregions[j].erasesize; + ++erase_region_p; + } + position += subdev[i]->eraseregions[j].numblocks * curr_erasesize; + } + } + } + /* Now write the final entry */ + erase_region_p->offset = begin; + erase_region_p->erasesize = curr_erasesize; + erase_region_p->numblocks = (position - begin) / curr_erasesize; + } + + return &concat->mtd; +} + +/* + * This function destroys an MTD object obtained from concat_mtd_devs() + */ + +void mtd_concat_destroy(struct mtd_info *mtd) +{ + struct mtd_concat *concat = CONCAT(mtd); + if(concat->mtd.numeraseregions) + kfree(concat->mtd.eraseregions); + kfree(concat); +} + + +EXPORT_SYMBOL(mtd_concat_create); +EXPORT_SYMBOL(mtd_concat_destroy); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Kaiser "); +MODULE_DESCRIPTION("Generic support for concatenating of MTD devices"); diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c --- a/drivers/mtd/nftlcore.c Tue Oct 15 20:29:11 2002 +++ b/drivers/mtd/nftlcore.c Tue Oct 15 20:29:11 2002 @@ -74,7 +74,7 @@ } nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL); - gd = alloc_disk(); + gd = alloc_disk(1 << NFTL_PARTN_BITS); if (!nftl || !gd) { kfree(nftl); put_disk(gd); @@ -132,7 +132,6 @@ sprintf(gd->disk_name, "nftl%c", 'a' + firstfree); gd->major = MAJOR_NR; gd->first_minor = firstfree << NFTL_PARTN_BITS; - gd->minor_shift = NFTL_PARTN_BITS; set_capacity(gd, nftl->nr_sects); nftl->disk = gd; add_disk(gd); @@ -771,7 +770,6 @@ return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; } case BLKFLSBUF: - if (!capable(CAP_SYS_ADMIN)) return -EACCES; fsync_bdev(inode->i_bdev); invalidate_bdev(inode->i_bdev, 0); if (nftl->mtd->sync) diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c --- a/drivers/net/pppoe.c Tue Oct 15 20:29:17 2002 +++ b/drivers/net/pppoe.c Tue Oct 15 20:29:17 2002 @@ -5,7 +5,7 @@ * PPPoE --- PPP over Ethernet (RFC 2516) * * - * Version: 0.6.10 + * Version: 0.6.11 * * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme * 030700 : Fixed connect logic to allow for disconnect. @@ -35,6 +35,7 @@ * 121301 : New ppp channels interface; cannot unregister a channel * from interrupts. Thus, we mark the socket as a ZOMBIE * and do the unregistration later. + * 081002 : seq_file support for proc stuff -acme * * Author: Michal Ostrowski * Contributors: @@ -75,6 +76,7 @@ #include #include #include +#include @@ -773,7 +775,7 @@ } -int pppoe_sendmsg(struct socket *sock, struct msghdr *m, +int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm) { struct sk_buff *skb = NULL; @@ -934,7 +936,7 @@ struct ppp_channel_ops pppoe_chan_ops = { pppoe_xmit , NULL }; -int pppoe_rcvmsg(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm) +int pppoe_rcvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm) { struct sock *sk = sock->sk; struct sk_buff *skb = NULL; @@ -974,63 +976,102 @@ return error; } -int pppoe_proc_info(char *buffer, char **start, off_t offset, int length) +#ifdef CONFIG_PROC_FS +static int pppoe_seq_show(struct seq_file *seq, void *v) { struct pppox_opt *po; - int len = 0; - off_t pos = 0; - off_t begin = 0; - int size; - int i; + char *dev_name; - len += sprintf(buffer, - "Id Address Device\n"); - pos = len; + if (v == (void *)1) { + seq_puts(seq, "Id Address Device\n"); + goto out; + } - write_lock_bh(&pppoe_hash_lock); + po = v; + dev_name = po->pppoe_pa.dev; + + seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n", + po->pppoe_pa.sid, + po->pppoe_pa.remote[0], po->pppoe_pa.remote[1], + po->pppoe_pa.remote[2], po->pppoe_pa.remote[3], + po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name); +out: + return 0; +} - for (i = 0; i < PPPOE_HASH_SIZE; i++) { +static __inline__ struct pppox_opt *pppoe_get_idx(loff_t pos) +{ + struct pppox_opt *po = NULL; + int i = 0; + + for (; i < PPPOE_HASH_SIZE; i++) { po = item_hash_table[i]; while (po) { - char *dev = po->pppoe_pa.dev; + if (!pos--) + goto out; + po = po->next; + } + } +out: + return po; +} - size = sprintf(buffer + len, - "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n", - po->pppoe_pa.sid, - po->pppoe_pa.remote[0], - po->pppoe_pa.remote[1], - po->pppoe_pa.remote[2], - po->pppoe_pa.remote[3], - po->pppoe_pa.remote[4], - po->pppoe_pa.remote[5], - dev); - len += size; - pos += size; - if (pos < offset) { - len = 0; - begin = pos; - } +static void *pppoe_seq_start(struct seq_file *seq, loff_t *pos) +{ + loff_t l = *pos; - if (pos > offset + length) - break; + read_lock_bh(&pppoe_hash_lock); + return l ? pppoe_get_idx(--l) : (void *)1; +} - po = po->next; +static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct pppox_opt *po; + + ++*pos; + if (v == (void *)1) { + po = pppoe_get_idx(0); + goto out; + } + po = v; + po = po->next; + if (!po) { + int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote); + + while (++hash < PPPOE_HASH_SIZE) { + po = item_hash_table[hash]; + if (po) + break; } + } +out: + return po; +} - if (po) - break; - } - write_unlock_bh(&pppoe_hash_lock); +static void pppoe_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&pppoe_hash_lock); +} + +struct seq_operations pppoe_seq_ops = { + .start = pppoe_seq_start, + .next = pppoe_seq_next, + .stop = pppoe_seq_stop, + .show = pppoe_seq_show, +}; - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - if (len < 0) - len = 0; - return len; +static int pppoe_seq_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &pppoe_seq_ops); } +static struct file_operations pppoe_seq_fops = { + .open = pppoe_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif /* CONFIG_PROC_FS */ struct proto_ops pppoe_ops = { .family = AF_PPPOX, @@ -1061,13 +1102,28 @@ { int err = register_pppox_proto(PX_PROTO_OE, &pppoe_proto); - if (err == 0) { - dev_add_pack(&pppoes_ptype); - dev_add_pack(&pppoed_ptype); - register_netdevice_notifier(&pppoe_notifier); - proc_net_create("pppoe", 0, pppoe_proc_info); - } + if (err) + goto out; +#ifdef CONFIG_PROC_FS +{ + struct proc_dir_entry *p = create_proc_entry("pppoe", S_IRUGO, + proc_net); + err = -ENOMEM; + if (!p) + goto out_unregister; + + p->proc_fops = &pppoe_seq_fops; + err = 0; +} +#endif /* CONFIG_PROC_FS */ + dev_add_pack(&pppoes_ptype); + dev_add_pack(&pppoed_ptype); + register_netdevice_notifier(&pppoe_notifier); +out: return err; +out_unregister: + unregister_pppox_proto(PX_PROTO_OE); + goto out; } void __exit pppoe_exit(void) @@ -1076,7 +1132,7 @@ dev_remove_pack(&pppoes_ptype); dev_remove_pack(&pppoed_ptype); unregister_netdevice_notifier(&pppoe_notifier); - proc_net_remove("pppoe"); + remove_proc_entry("pppoe", proc_net); } module_init(pppoe_init); diff -Nru a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c --- a/drivers/net/wan/syncppp.c Tue Oct 15 20:29:15 2002 +++ b/drivers/net/wan/syncppp.c Tue Oct 15 20:29:15 2002 @@ -1284,12 +1284,12 @@ { struct sppp *sp = (struct sppp*) arg; unsigned long flags; - save_flags(flags); - cli(); + + spin_lock_irqsave(&spppq_lock, flags); sp->pp_flags &= ~PP_TIMO; if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { - restore_flags(flags); + spin_unlock_irqrestore(&spppq_lock, flags); return; } switch (sp->lcp.state) { @@ -1328,7 +1328,7 @@ } break; } - restore_flags(flags); + spin_unlock_irqrestore(&spppq_lock, flags); } static char *sppp_lcp_type_name (u8 type) diff -Nru a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/buffer_sync.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,394 @@ +/** + * @file buffer_sync.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * + * This is the core of the buffer management. Each + * CPU buffer is processed and entered into the + * global event buffer. Such processing is necessary + * in several circumstances, mentioned below. + * + * The processing does the job of converting the + * transitory EIP value into a persistent dentry/offset + * value that the profiler can record at its leisure. + * + * See fs/dcookies.c for a description of the dentry/offset + * objects. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "event_buffer.h" +#include "cpu_buffer.h" +#include "oprofile_stats.h" + +#define DEFAULT_EXPIRE (HZ / 4) + +static void wq_sync_buffers(void *); +static DECLARE_WORK(sync_wq, wq_sync_buffers, 0); + +static struct timer_list sync_timer; +static void timer_ping(unsigned long data); +static void sync_cpu_buffers(void); + + +/* We must make sure to process every entry in the CPU buffers + * before a task got the PF_EXITING flag, otherwise we will hold + * references to a possibly freed task_struct. We are safe with + * samples past the PF_EXITING point in do_exit(), because we + * explicitly check for that in cpu_buffer.c + */ +static int exit_task_notify(struct notifier_block * self, unsigned long val, void * data) +{ + sync_cpu_buffers(); + return 0; +} + +/* There are two cases of tasks modifying task->mm->mmap list we + * must concern ourselves with. First, when a task is about to + * exit (exit_mmap()), we should process the buffer to deal with + * any samples in the CPU buffer, before we lose the ->mmap information + * we need. Second, a task may unmap (part of) an executable mmap, + * so we want to process samples before that happens too + */ +static int mm_notify(struct notifier_block * self, unsigned long val, void * data) +{ + sync_cpu_buffers(); + return 0; +} + + +static struct notifier_block exit_task_nb = { + .notifier_call = exit_task_notify, +}; + +static struct notifier_block exec_unmap_nb = { + .notifier_call = mm_notify, +}; + +static struct notifier_block exit_mmap_nb = { + .notifier_call = mm_notify, +}; + + +int sync_start(void) +{ + int err = profile_event_register(EXIT_TASK, &exit_task_nb); + if (err) + goto out; + err = profile_event_register(EXIT_MMAP, &exit_mmap_nb); + if (err) + goto out2; + err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb); + if (err) + goto out3; + + sync_timer.function = timer_ping; + sync_timer.expires = jiffies + DEFAULT_EXPIRE; + add_timer(&sync_timer); +out: + return err; +out3: + profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); +out2: + profile_event_unregister(EXIT_TASK, &exit_task_nb); + goto out; +} + + +void sync_stop(void) +{ + profile_event_unregister(EXIT_TASK, &exit_task_nb); + profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); + profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb); + del_timer_sync(&sync_timer); +} + + +/* Optimisation. We can manage without taking the dcookie sem + * because we cannot reach this code without at least one + * dcookie user still being registered (namely, the reader + * of the event buffer). */ +static inline u32 fast_get_dcookie(struct dentry * dentry, + struct vfsmount * vfsmnt) +{ + u32 cookie; + + if (dentry->d_cookie) + return (u32)dentry; + get_dcookie(dentry, vfsmnt, &cookie); + return cookie; +} + + +/* Look up the dcookie for the task's first VM_EXECUTABLE mapping, + * which corresponds loosely to "application name". This is + * not strictly necessary but allows oprofile to associate + * shared-library samples with particular applications + */ +static u32 get_exec_dcookie(struct mm_struct * mm) +{ + u32 cookie = 0; + struct vm_area_struct * vma; + + if (!mm) + goto out; + + for (vma = mm->mmap; vma; vma = vma->vm_next) { + if (!vma->vm_file) + continue; + if (!vma->vm_flags & VM_EXECUTABLE) + continue; + cookie = fast_get_dcookie(vma->vm_file->f_dentry, + vma->vm_file->f_vfsmnt); + break; + } + +out: + return cookie; +} + + +/* Convert the EIP value of a sample into a persistent dentry/offset + * pair that can then be added to the global event buffer. We make + * sure to do this lookup before a mm->mmap modification happens so + * we don't lose track. + */ +static u32 lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset) +{ + u32 cookie = 0; + struct vm_area_struct * vma; + + for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) { + if (!vma) + goto out; + + if (!vma->vm_file) + continue; + + if (addr < vma->vm_start || addr >= vma->vm_end) + continue; + + cookie = fast_get_dcookie(vma->vm_file->f_dentry, + vma->vm_file->f_vfsmnt); + *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start; + break; + } +out: + return cookie; +} + + +static u32 last_cookie = ~0UL; + +static void add_cpu_switch(int i) +{ + add_event_entry(ESCAPE_CODE); + add_event_entry(CPU_SWITCH_CODE); + add_event_entry(i); + last_cookie = ~0UL; +} + + +static void add_ctx_switch(pid_t pid, u32 cookie) +{ + add_event_entry(ESCAPE_CODE); + add_event_entry(CTX_SWITCH_CODE); + add_event_entry(pid); + add_event_entry(cookie); +} + + +static void add_cookie_switch(u32 cookie) +{ + add_event_entry(ESCAPE_CODE); + add_event_entry(COOKIE_SWITCH_CODE); + add_event_entry(cookie); +} + + +static void add_sample_entry(unsigned long offset, unsigned long event) +{ + add_event_entry(offset); + add_event_entry(event); +} + + +static void add_us_sample(struct mm_struct * mm, struct op_sample * s) +{ + u32 cookie; + off_t offset; + + cookie = lookup_dcookie(mm, s->eip, &offset); + + if (!cookie) + return; + + if (cookie != last_cookie) { + add_cookie_switch(cookie); + last_cookie = cookie; + } + + add_sample_entry(offset, s->event); +} + + +static inline int is_kernel(unsigned long val) +{ + return val > __PAGE_OFFSET; +} + + +/* Add a sample to the global event buffer. If possible the + * sample is converted into a persistent dentry/offset pair + * for later lookup from userspace. + */ +static void add_sample(struct mm_struct * mm, struct op_sample * s) +{ + if (is_kernel(s->eip)) { + add_sample_entry(s->eip, s->event); + } else if (mm) { + add_us_sample(mm, s); + } +} + + +static void release_mm(struct mm_struct * mm) +{ + if (mm) + up_read(&mm->mmap_sem); +} + + +/* Take the task's mmap_sem to protect ourselves from + * races when we do lookup_dcookie(). + */ +static struct mm_struct * take_task_mm(struct task_struct * task) +{ + struct mm_struct * mm; + task_lock(task); + mm = task->mm; + task_unlock(task); + + /* if task->mm !NULL, mm_count must be at least 1. It cannot + * drop to 0 without the task exiting, which will have to sleep + * on buffer_sem first. So we do not need to mark mm_count + * ourselves. + */ + if (mm) { + /* More ugliness. If a task took its mmap + * sem then came to sleep on buffer_sem we + * will deadlock waiting for it. So we can + * but try. This will lose samples :/ + */ + if (!down_read_trylock(&mm->mmap_sem)) { + /* FIXME: this underestimates samples lost */ + atomic_inc(&oprofile_stats.sample_lost_mmap_sem); + mm = NULL; + } + } + + return mm; +} + + +static inline int is_ctx_switch(unsigned long val) +{ + return val == ~0UL; +} + + +/* Sync one of the CPU's buffers into the global event buffer. + * Here we need to go through each batch of samples punctuated + * by context switch notes, taking the task's mmap_sem and doing + * lookup in task->mm->mmap to convert EIP into dcookie/offset + * value. + */ +static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf) +{ + struct mm_struct * mm = 0; + struct task_struct * new; + u32 cookie; + int i; + + for (i=0; i < cpu_buf->pos; ++i) { + struct op_sample * s = &cpu_buf->buffer[i]; + + if (is_ctx_switch(s->eip)) { + new = (struct task_struct *)s->event; + + release_mm(mm); + mm = take_task_mm(new); + + cookie = get_exec_dcookie(mm); + add_ctx_switch(new->pid, cookie); + } else { + add_sample(mm, s); + } + } + release_mm(mm); + + cpu_buf->pos = 0; +} + + +/* Process each CPU's local buffer into the global + * event buffer. + */ +static void sync_cpu_buffers(void) +{ + int i; + + down(&buffer_sem); + + for (i = 0; i < NR_CPUS; ++i) { + struct oprofile_cpu_buffer * cpu_buf; + + if (!cpu_possible(i)) + continue; + + cpu_buf = &cpu_buffer[i]; + + /* We take a spin lock even though we might + * sleep. It's OK because other users are try + * lockers only, and this region is already + * protected by buffer_sem. It's raw to prevent + * the preempt bogometer firing. Fruity, huh ? */ + _raw_spin_lock(&cpu_buf->int_lock); + add_cpu_switch(i); + sync_buffer(cpu_buf); + _raw_spin_unlock(&cpu_buf->int_lock); + } + + up(&buffer_sem); + + mod_timer(&sync_timer, jiffies + DEFAULT_EXPIRE); +} + + +static void wq_sync_buffers(void * data) +{ + sync_cpu_buffers(); +} + + +/* It is possible that we could have no munmap() or + * other events for a period of time. This will lead + * the CPU buffers to overflow and lose samples and + * context switches. We try to reduce the problem + * by timing out when nothing happens for a while. + */ +static void timer_ping(unsigned long data) +{ + schedule_work(&sync_wq); + /* timer is re-added by the scheduled task */ +} diff -Nru a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/buffer_sync.h Tue Oct 15 20:29:24 2002 @@ -0,0 +1,19 @@ +/** + * @file buffer_sync.h + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef OPROFILE_BUFFER_SYNC_H +#define OPROFILE_BUFFER_SYNC_H + +/* add the necessary profiling hooks */ +int sync_start(void); + +/* remove the hooks */ +void sync_stop(void); + +#endif /* OPROFILE_BUFFER_SYNC_H */ diff -Nru a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/cpu_buffer.c Tue Oct 15 20:29:23 2002 @@ -0,0 +1,135 @@ +/** + * @file cpu_buffer.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * + * Each CPU has a local buffer that stores PC value/event + * pairs. We also log context switches when we notice them. + * Eventually each CPU's buffer is processed into the global + * event buffer by sync_cpu_buffers(). + * + * We use a local buffer for two reasons: an NMI or similar + * interrupt cannot synchronise, and high sampling rates + * would lead to catastrophic global synchronisation if + * a global buffer was used. + */ + +#include +#include +#include + +#include "cpu_buffer.h" +#include "oprof.h" +#include "oprofile_stats.h" + +struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned; + +static unsigned long buffer_size; + +static void __free_cpu_buffers(int num) +{ + int i; + + for (i=0; i < num; ++i) { + struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + + if (!cpu_possible(i)) + continue; + + vfree(b->buffer); + } +} + + +int alloc_cpu_buffers(void) +{ + int i; + + buffer_size = fs_cpu_buffer_size; + + for (i=0; i < NR_CPUS; ++i) { + struct oprofile_cpu_buffer * b = &cpu_buffer[i]; + + if (!cpu_possible(i)) + continue; + + b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size); + if (!b->buffer) + goto fail; + + spin_lock_init(&b->int_lock); + b->pos = 0; + b->last_task = 0; + b->sample_received = 0; + b->sample_lost_locked = 0; + b->sample_lost_overflow = 0; + } + return 0; +fail: + __free_cpu_buffers(i); + return -ENOMEM; +} + + +void free_cpu_buffers(void) +{ + __free_cpu_buffers(NR_CPUS); +} + + +/* Note we can't use a semaphore here as this is supposed to + * be safe from any context. Instead we trylock the CPU's int_lock. + * int_lock is taken by the processing code in sync_cpu_buffers() + * so we avoid disturbing that. + */ +void oprofile_add_sample(unsigned long eip, unsigned long event, int cpu) +{ + struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu]; + struct task_struct * task; + + /* temporary ? */ + BUG_ON(!oprofile_started); + + cpu_buf->sample_received++; + + if (!spin_trylock(&cpu_buf->int_lock)) { + cpu_buf->sample_lost_locked++; + return; + } + + if (cpu_buf->pos > buffer_size - 2) { + cpu_buf->sample_lost_overflow++; + goto out; + } + + task = current; + + /* notice a task switch */ + if (cpu_buf->last_task != task) { + cpu_buf->last_task = task; + if (!(task->flags & PF_EXITING)) { + cpu_buf->buffer[cpu_buf->pos].eip = ~0UL; + cpu_buf->buffer[cpu_buf->pos].event = (unsigned long)task; + cpu_buf->pos++; + } + } + + /* If the task is exiting it's not safe to take a sample + * as the task_struct is about to be freed. We can't just + * notify at release_task() time because of CLONE_DETACHED + * tasks that release_task() themselves. + */ + if (task->flags & PF_EXITING) { + cpu_buf->sample_lost_task_exit++; + goto out; + } + + cpu_buf->buffer[cpu_buf->pos].eip = eip; + cpu_buf->buffer[cpu_buf->pos].event = event; + cpu_buf->pos++; +out: + spin_unlock(&cpu_buf->int_lock); +} diff -Nru a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/cpu_buffer.h Tue Oct 15 20:29:25 2002 @@ -0,0 +1,45 @@ +/** + * @file cpu_buffer.h + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef OPROFILE_CPU_BUFFER_H +#define OPROFILE_CPU_BUFFER_H + +#include +#include + +struct task_struct; + +/* allocate a sample buffer for each CPU */ +int alloc_cpu_buffers(void); + +void free_cpu_buffers(void); + +/* CPU buffer is composed of such entries (which are + * also used for context switch notes) + */ +struct op_sample { + unsigned long eip; + unsigned long event; +}; + +struct oprofile_cpu_buffer { + spinlock_t int_lock; + /* protected by int_lock */ + unsigned long pos; + struct task_struct * last_task; + struct op_sample * buffer; + unsigned long sample_received; + unsigned long sample_lost_locked; + unsigned long sample_lost_overflow; + unsigned long sample_lost_task_exit; +} ____cacheline_aligned; + +extern struct oprofile_cpu_buffer cpu_buffer[]; + +#endif /* OPROFILE_CPU_BUFFER_H */ diff -Nru a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/event_buffer.c Tue Oct 15 20:29:23 2002 @@ -0,0 +1,186 @@ +/** + * @file event_buffer.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * + * This is the global event buffer that the user-space + * daemon reads from. The event buffer is an untyped array + * of unsigned longs. Entries are prefixed by the + * escape value ESCAPE_CODE followed by an identifying code. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "event_buffer.h" +#include "cpu_buffer.h" +#include "oprof.h" +#include "oprofile_stats.h" + +DECLARE_MUTEX(buffer_sem); + +static unsigned long buffer_opened; +static DECLARE_WAIT_QUEUE_HEAD(buffer_wait); +static unsigned long * event_buffer; +static unsigned long buffer_size; +static unsigned long buffer_watershed; +static size_t buffer_pos; +/* atomic_t because wait_event checks it outside of buffer_sem */ +static atomic_t buffer_ready = ATOMIC_INIT(0); + +/* Add an entry to the event buffer. When we + * get near to the end we wake up the process + * sleeping on the read() of the file. + */ +void add_event_entry(unsigned long value) +{ + if (buffer_pos == buffer_size) { + atomic_inc(&oprofile_stats.event_lost_overflow); + return; + } + + event_buffer[buffer_pos] = value; + if (++buffer_pos == buffer_size - buffer_watershed) { + atomic_set(&buffer_ready, 1); + wake_up(&buffer_wait); + } +} + + +/* Wake up the waiting process if any. This happens + * on "echo 0 >/dev/oprofile/enable" so the daemon + * processes the data remaining in the event buffer. + */ +void wake_up_buffer_waiter(void) +{ + down(&buffer_sem); + atomic_set(&buffer_ready, 1); + wake_up(&buffer_wait); + up(&buffer_sem); +} + + +int alloc_event_buffer(void) +{ + int err = -ENOMEM; + + spin_lock(&oprofilefs_lock); + buffer_size = fs_buffer_size; + buffer_watershed = fs_buffer_watershed; + spin_unlock(&oprofilefs_lock); + + if (buffer_watershed >= buffer_size) + return -EINVAL; + + event_buffer = vmalloc(sizeof(unsigned long) * buffer_size); + if (!event_buffer) + goto out; + + err = 0; +out: + return err; +} + + +void free_event_buffer(void) +{ + vfree(event_buffer); +} + + +int event_buffer_open(struct inode * inode, struct file * file) +{ + int err = -EPERM; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (test_and_set_bit(0, &buffer_opened)) + return -EBUSY; + + /* Register as a user of dcookies + * to ensure they persist for the lifetime of + * the open event file + */ + err = -EINVAL; + file->private_data = dcookie_register(); + if (!file->private_data) + goto out; + + if ((err = oprofile_setup())) + goto fail; + + /* NB: the actual start happens from userspace + * echo 1 >/dev/oprofile/enable + */ + + return 0; + +fail: + dcookie_unregister(file->private_data); +out: + clear_bit(0, &buffer_opened); + return err; +} + + +int event_buffer_release(struct inode * inode, struct file * file) +{ + oprofile_stop(); + oprofile_shutdown(); + dcookie_unregister(file->private_data); + buffer_pos = 0; + atomic_set(&buffer_ready, 0); + clear_bit(0, &buffer_opened); + return 0; +} + + +ssize_t event_buffer_read(struct file * file, char * buf, size_t count, loff_t * offset) +{ + int retval = -EINVAL; + size_t const max = buffer_size * sizeof(unsigned long); + + /* handling partial reads is more trouble than it's worth */ + if (count != max || *offset) + return -EINVAL; + + /* wait for the event buffer to fill up with some data */ + wait_event_interruptible(buffer_wait, atomic_read(&buffer_ready)); + if (signal_pending(current)) + return -EINTR; + + down(&buffer_sem); + + atomic_set(&buffer_ready, 0); + + retval = -EFAULT; + + count = buffer_pos * sizeof(unsigned long); + + if (copy_to_user(buf, event_buffer, count)) + goto out; + + retval = count; + buffer_pos = 0; + +out: + up(&buffer_sem); + return retval; +} + +struct file_operations event_buffer_fops = { + .open = event_buffer_open, + .release = event_buffer_release, + .read = event_buffer_read, +}; diff -Nru a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/event_buffer.h Tue Oct 15 20:29:24 2002 @@ -0,0 +1,42 @@ +/** + * @file event_buffer.h + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef EVENT_BUFFER_H +#define EVENT_BUFFER_H + +#include +#include + +int alloc_event_buffer(void); + +void free_event_buffer(void); + +/* wake up the process sleeping on the event file */ +void wake_up_buffer_waiter(void); + +/* Each escaped entry is prefixed by ESCAPE_CODE + * then one of the following codes, then the + * relevant data. + */ +#define ESCAPE_CODE ~0UL +#define CTX_SWITCH_CODE 1 +#define CPU_SWITCH_CODE 2 +#define COOKIE_SWITCH_CODE 3 + +/* add data to the event buffer */ +void add_event_entry(unsigned long data); + +extern struct file_operations event_buffer_fops; + +/* mutex between sync_cpu_buffers() and the + * file reading code. + */ +extern struct semaphore buffer_sem; + +#endif /* EVENT_BUFFER_H */ diff -Nru a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/oprof.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,153 @@ +/** + * @file oprof.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oprof.h" +#include "event_buffer.h" +#include "cpu_buffer.h" +#include "buffer_sync.h" +#include "oprofile_stats.h" + +struct oprofile_operations * oprofile_ops; +enum oprofile_cpu oprofile_cpu_type; +unsigned long oprofile_started; +static unsigned long is_setup; +static DECLARE_MUTEX(start_sem); + +int oprofile_setup(void) +{ + int err; + + if ((err = alloc_cpu_buffers())) + goto out; + + if ((err = alloc_event_buffer())) + goto out1; + + if (oprofile_ops->setup && (err = oprofile_ops->setup())) + goto out2; + + /* Note even though this starts part of the + * profiling overhead, it's necessary to prevent + * us missing task deaths and eventually oopsing + * when trying to process the event buffer. + */ + if ((err = sync_start())) + goto out3; + + down(&start_sem); + is_setup = 1; + up(&start_sem); + return 0; + +out3: + if (oprofile_ops->shutdown) + oprofile_ops->shutdown(); +out2: + free_event_buffer(); +out1: + free_cpu_buffers(); +out: + return err; +} + + +/* Actually start profiling (echo 1>/dev/oprofile/enable) */ +int oprofile_start(void) +{ + int err = -EINVAL; + + down(&start_sem); + + if (!is_setup) + goto out; + + err = 0; + + if (oprofile_started) + goto out; + + if ((err = oprofile_ops->start())) + goto out; + + oprofile_started = 1; + oprofile_reset_stats(); +out: + up(&start_sem); + return err; +} + + +/* echo 0>/dev/oprofile/enable */ +void oprofile_stop(void) +{ + down(&start_sem); + if (!oprofile_started) + goto out; + oprofile_ops->stop(); + oprofile_started = 0; + /* wake up the daemon to read what remains */ + wake_up_buffer_waiter(); +out: + up(&start_sem); +} + + +void oprofile_shutdown(void) +{ + sync_stop(); + if (oprofile_ops->shutdown) + oprofile_ops->shutdown(); + /* down() is also necessary to synchronise all pending events + * before freeing */ + down(&buffer_sem); + is_setup = 0; + up(&buffer_sem); + free_event_buffer(); + free_cpu_buffers(); +} + + +static int __init oprofile_init(void) +{ + int err; + + /* Architecture must fill in the interrupt ops and the + * logical CPU type. + */ + err = oprofile_arch_init(&oprofile_ops, &oprofile_cpu_type); + if (err) + goto out; + + err = oprofilefs_register(); + if (err) + goto out; + +out: + return err; +} + + +static void __exit oprofile_exit(void) +{ + oprofilefs_unregister(); +} + +MODULE_LICENSE("GPL"); +module_init(oprofile_init); +module_exit(oprofile_exit); diff -Nru a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/oprof.h Tue Oct 15 20:29:25 2002 @@ -0,0 +1,34 @@ +/** + * @file oprof.h + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef OPROF_H +#define OPROF_H + +#include +#include + +int oprofile_setup(void); +void oprofile_shutdown(void); + +int oprofilefs_register(void); +void oprofilefs_unregister(void); + +int oprofile_start(void); +void oprofile_stop(void); + +extern unsigned long fs_buffer_size; +extern unsigned long fs_cpu_buffer_size; +extern unsigned long fs_buffer_watershed; +extern enum oprofile_cpu oprofile_cpu_type; +extern struct oprofile_operations * oprofile_ops; +extern unsigned long oprofile_started; + +void oprofile_create_files(struct super_block * sb, struct dentry * root); + +#endif /* OPROF_H */ diff -Nru a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/oprofile_files.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,91 @@ +/** + * @file oprofile_files.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include + +#include "oprof.h" +#include "event_buffer.h" +#include "oprofile_stats.h" + +unsigned long fs_buffer_size = 131072; +unsigned long fs_cpu_buffer_size = 8192; +unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */ + + +static int simple_open(struct inode * inode, struct file * filp) +{ + return 0; +} + + +static ssize_t cpu_type_read(struct file * file, char * buf, size_t count, loff_t * offset) +{ + unsigned long cpu_type = oprofile_cpu_type; + + return oprofilefs_ulong_to_user(&cpu_type, buf, count, offset); +} + + +static struct file_operations cpu_type_fops = { + .open = simple_open, + .read = cpu_type_read, +}; + + +static ssize_t enable_read(struct file * file, char * buf, size_t count, loff_t * offset) +{ + return oprofilefs_ulong_to_user(&oprofile_started, buf, count, offset); +} + + +static ssize_t enable_write(struct file *file, char const * buf, size_t count, loff_t * offset) +{ + unsigned long val; + int retval; + + if (*offset) + return -EINVAL; + + retval = oprofilefs_ulong_from_user(&val, buf, count); + if (retval) + return retval; + + if (val) + retval = oprofile_start(); + else + oprofile_stop(); + + if (retval) + return retval; + return count; +} + + +static struct file_operations enable_fops = { + .open = simple_open, + .read = enable_read, + .write = enable_write, +}; + + +void oprofile_create_files(struct super_block * sb, struct dentry * root) +{ + oprofilefs_create_file(sb, root, "enable", &enable_fops); + oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops); + oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); + oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size); + oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); + oprofile_create_stats_files(sb, root); + if (oprofile_ops->create_files) + oprofile_ops->create_files(sb, root); +} diff -Nru a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/oprofile_stats.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,77 @@ +/** + * @file oprofile_stats.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include + +#include "oprofile_stats.h" +#include "cpu_buffer.h" + +struct oprofile_stat_struct oprofile_stats; + +void oprofile_reset_stats(void) +{ + struct oprofile_cpu_buffer * cpu_buf; + int i; + + for (i = 0; i < NR_CPUS; ++i) { + if (!cpu_possible(i)) + continue; + + cpu_buf = &cpu_buffer[i]; + cpu_buf->sample_received = 0; + cpu_buf->sample_lost_locked = 0; + cpu_buf->sample_lost_overflow = 0; + cpu_buf->sample_lost_task_exit = 0; + } + + atomic_set(&oprofile_stats.sample_lost_mmap_sem, 0); + atomic_set(&oprofile_stats.event_lost_overflow, 0); +} + + +void oprofile_create_stats_files(struct super_block * sb, struct dentry * root) +{ + struct oprofile_cpu_buffer * cpu_buf; + struct dentry * cpudir; + struct dentry * dir; + char buf[10]; + int i; + + dir = oprofilefs_mkdir(sb, root, "stats"); + if (!dir) + return; + + for (i = 0; i < NR_CPUS; ++i) { + if (!cpu_possible(i)) + continue; + + cpu_buf = &cpu_buffer[i]; + snprintf(buf, 6, "cpu%d", i); + cpudir = oprofilefs_mkdir(sb, dir, buf); + + /* Strictly speaking access to these ulongs is racy, + * but we can't simply lock them, and they are + * informational only. + */ + oprofilefs_create_ro_ulong(sb, cpudir, "sample_received", + &cpu_buf->sample_received); + oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_locked", + &cpu_buf->sample_lost_locked); + oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_overflow", + &cpu_buf->sample_lost_overflow); + oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_task_exit", + &cpu_buf->sample_lost_task_exit); + } + + oprofilefs_create_ro_atomic(sb, dir, "sample_lost_mmap_sem", + &oprofile_stats.sample_lost_mmap_sem); + oprofilefs_create_ro_atomic(sb, dir, "event_lost_overflow", + &oprofile_stats.event_lost_overflow); +} diff -Nru a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/oprofile_stats.h Tue Oct 15 20:29:25 2002 @@ -0,0 +1,31 @@ +/** + * @file oprofile_stats.h + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef OPROFILE_STATS_H +#define OPROFILE_STATS_H + +#include + +struct oprofile_stat_struct { + atomic_t sample_lost_mmap_sem; + atomic_t event_lost_overflow; +}; + +extern struct oprofile_stat_struct oprofile_stats; + +/* reset all stats to zero */ +void oprofile_reset_stats(void); + +struct super_block; +struct dentry; + +/* create the stats/ dir */ +void oprofile_create_stats_files(struct super_block * sb, struct dentry * root); + +#endif /* OPROFILE_STATS_H */ diff -Nru a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/oprofile/oprofilefs.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,306 @@ +/** + * @file oprofilefs.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + * + * A simple filesystem for configuration and + * access of oprofile. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "oprof.h" + +#define OPROFILEFS_MAGIC 0x6f70726f + +spinlock_t oprofilefs_lock = SPIN_LOCK_UNLOCKED; + +static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode) +{ + struct inode * inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + } + return inode; +} + + +static struct super_operations s_ops = { + .statfs = simple_statfs, + .drop_inode = generic_delete_inode, +}; + +#define TMPBUFSIZE 50 + +ssize_t oprofilefs_ulong_to_user(unsigned long * val, char * buf, size_t count, loff_t * offset) +{ + char tmpbuf[TMPBUFSIZE]; + size_t maxlen; + + if (!count) + return 0; + + spin_lock(&oprofilefs_lock); + maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", *val); + spin_unlock(&oprofilefs_lock); + if (maxlen > TMPBUFSIZE) + maxlen = TMPBUFSIZE; + + if (*offset > maxlen) + return 0; + + if (count > maxlen - *offset) + count = maxlen - *offset; + + if (copy_to_user(buf, tmpbuf + *offset, count)) + return -EFAULT; + + *offset += count; + + return count; +} + + +int oprofilefs_ulong_from_user(unsigned long * val, char const * buf, size_t count) +{ + char tmpbuf[TMPBUFSIZE]; + + if (!count) + return 0; + + if (count > TMPBUFSIZE - 1) + return -EINVAL; + + memset(tmpbuf, 0x0, TMPBUFSIZE); + + if (copy_from_user(tmpbuf, buf, count)) + return -EFAULT; + + spin_lock(&oprofilefs_lock); + *val = simple_strtoul(tmpbuf, NULL, 10); + spin_unlock(&oprofilefs_lock); + return 0; +} + + +static ssize_t ulong_read_file(struct file * file, char * buf, size_t count, loff_t * offset) +{ + return oprofilefs_ulong_to_user(file->private_data, buf, count, offset); +} + + +static ssize_t ulong_write_file(struct file * file, char const * buf, size_t count, loff_t * offset) +{ + unsigned long * value = file->private_data; + int retval; + + if (*offset) + return -EINVAL; + + retval = oprofilefs_ulong_from_user(value, buf, count); + + if (retval) + return retval; + return count; +} + + +static int default_open(struct inode * inode, struct file * filp) +{ + if (inode->u.generic_ip) + filp->private_data = inode->u.generic_ip; + return 0; +} + + +static struct file_operations ulong_fops = { + .read = ulong_read_file, + .write = ulong_write_file, + .open = default_open, +}; + + +static struct file_operations ulong_ro_fops = { + .read = ulong_read_file, + .open = default_open, +}; + + +static struct dentry * __oprofilefs_create_file(struct super_block * sb, + struct dentry * root, char const * name, struct file_operations * fops) +{ + struct dentry * dentry; + struct inode * inode; + struct qstr qname; + qname.name = name; + qname.len = strlen(name); + qname.hash = full_name_hash(qname.name, qname.len); + dentry = d_alloc(root, &qname); + if (!dentry) + return 0; + inode = oprofilefs_get_inode(sb, S_IFREG | 0644); + if (!inode) { + dput(dentry); + return 0; + } + inode->i_fop = fops; + d_add(dentry, inode); + return dentry; +} + + +int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, + char const * name, unsigned long * val) +{ + struct dentry * d = __oprofilefs_create_file(sb, root, name, &ulong_fops); + if (!d) + return -EFAULT; + + d->d_inode->u.generic_ip = val; + return 0; +} + + +int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, + char const * name, unsigned long * val) +{ + struct dentry * d = __oprofilefs_create_file(sb, root, name, &ulong_ro_fops); + if (!d) + return -EFAULT; + + d->d_inode->u.generic_ip = val; + return 0; +} + + +static ssize_t atomic_read_file(struct file * file, char * buf, size_t count, loff_t * offset) +{ + atomic_t * aval = file->private_data; + unsigned long val = atomic_read(aval); + return oprofilefs_ulong_to_user(&val, buf, count, offset); +} + + +static struct file_operations atomic_ro_fops = { + .read = atomic_read_file, + .open = default_open, +}; + + +int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, + char const * name, atomic_t * val) +{ + struct dentry * d = __oprofilefs_create_file(sb, root, name, &atomic_ro_fops); + if (!d) + return -EFAULT; + + d->d_inode->u.generic_ip = val; + return 0; +} + + +int oprofilefs_create_file(struct super_block * sb, struct dentry * root, + char const * name, struct file_operations * fops) +{ + if (!__oprofilefs_create_file(sb, root, name, fops)) + return -EFAULT; + return 0; +} + + +struct dentry * oprofilefs_mkdir(struct super_block * sb, + struct dentry * root, char const * name) +{ + struct dentry * dentry; + struct inode * inode; + struct qstr qname; + qname.name = name; + qname.len = strlen(name); + qname.hash = full_name_hash(qname.name, qname.len); + dentry = d_alloc(root, &qname); + if (!dentry) + return 0; + inode = oprofilefs_get_inode(sb, S_IFDIR | 0755); + if (!inode) { + dput(dentry); + return 0; + } + inode->i_op = &simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + d_add(dentry, inode); + return dentry; +} + + +static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent) +{ + struct inode * root_inode; + struct dentry * root_dentry; + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = OPROFILEFS_MAGIC; + sb->s_op = &s_ops; + + root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755); + if (!root_inode) + return -ENOMEM; + root_inode->i_op = &simple_dir_inode_operations; + root_inode->i_fop = &simple_dir_operations; + root_dentry = d_alloc_root(root_inode); + if (!root_dentry) { + iput(root_inode); + return -ENOMEM; + } + + sb->s_root = root_dentry; + + oprofile_create_files(sb, root_dentry); + + // FIXME: verify kill_litter_super removes our dentries + return 0; +} + + +static struct super_block * oprofilefs_get_sb(struct file_system_type * fs_type, + int flags, char * dev_name, void * data) +{ + return get_sb_single(fs_type, flags, data, oprofilefs_fill_super); +} + + +static struct file_system_type oprofilefs_type = { + .owner = THIS_MODULE, + .name = "oprofilefs", + .get_sb = oprofilefs_get_sb, + .kill_sb = kill_litter_super, +}; + + +int __init oprofilefs_register(void) +{ + return register_filesystem(&oprofilefs_type); +} + + +void __exit oprofilefs_unregister(void) +{ + unregister_filesystem(&oprofilefs_type); +} diff -Nru a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c --- a/drivers/pcmcia/bulkmem.c Tue Oct 15 20:29:23 2002 +++ b/drivers/pcmcia/bulkmem.c Tue Oct 15 20:29:23 2002 @@ -211,7 +211,7 @@ retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT); } -static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase) +static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase) { erase_busy_t *busy; region_info_t *info; @@ -229,8 +229,10 @@ else { erase->State = 1; busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL); - if (!busy) - return CS_GENERAL_FAILURE; + if (!busy) { + erase->State = ERASE_FAILED; + return; + } busy->erase = erase; busy->client = handle; init_timer(&busy->timeout); @@ -240,7 +242,6 @@ retry_erase(busy, 0); } } - return CS_SUCCESS; } /* setup_erase_request */ /*====================================================================== @@ -325,7 +326,7 @@ ======================================================================*/ -static int setup_regions(client_handle_t handle, int attr, +static void setup_regions(client_handle_t handle, int attr, memory_handle_t *list) { int i, code, has_jedec, has_geo; @@ -340,7 +341,7 @@ code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE; if (read_tuple(handle, code, &device) != CS_SUCCESS) - return CS_GENERAL_FAILURE; + return; code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C; has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS); if (has_jedec && (device.ndev != jedec.nid)) { @@ -363,8 +364,10 @@ if ((device.dev[i].type != CISTPL_DTYPE_NULL) && (device.dev[i].size != 0)) { r = kmalloc(sizeof(*r), GFP_KERNEL); - if (!r) - return CS_GENERAL_FAILURE; + if (!r) { + printk(KERN_NOTICE "cs: setup_regions: kmalloc failed!\n"); + return; + } r->region_magic = REGION_MAGIC; r->state = 0; r->dev_info[0] = '\0'; @@ -389,7 +392,6 @@ } offset += device.dev[i].size; } - return CS_SUCCESS; } /* setup_regions */ /*====================================================================== @@ -423,10 +425,8 @@ if ((handle->Attributes & INFO_MASTER_CLIENT) && (!(s->state & SOCKET_REGION_INFO))) { - if (setup_regions(handle, 0, &s->c_region) != CS_SUCCESS) - return CS_GENERAL_FAILURE; - if (setup_regions(handle, 1, &s->a_region) != CS_SUCCESS) - return CS_GENERAL_FAILURE; + setup_regions(handle, 0, &s->c_region); + setup_regions(handle, 1, &s->a_region); s->state |= SOCKET_REGION_INFO; } diff -Nru a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h --- a/drivers/pcmcia/ricoh.h Tue Oct 15 20:29:16 2002 +++ b/drivers/pcmcia/ricoh.h Tue Oct 15 20:29:16 2002 @@ -75,6 +75,12 @@ #define RL5C46X_BCR_3E0_ENA 0x0800 #define RL5C46X_BCR_3E2_ENA 0x1000 +/* Bridge Configuration Register */ +#define RL5C4XX_CONFIG 0x80 /* 16 bit */ +#define RL5C4XX_CONFIG_IO_1_MODE 0x0200 +#define RL5C4XX_CONFIG_IO_0_MODE 0x0100 +#define RL5C4XX_CONFIG_PREFETCH 0x0001 + /* Misc Control Register */ #define RL5C4XX_MISC 0x0082 /* 16 bit */ #define RL5C4XX_MISC_HW_SUSPEND_ENA 0x0002 @@ -117,6 +123,7 @@ #define rl_ctl(socket) ((socket)->private[1]) #define rl_io(socket) ((socket)->private[2]) #define rl_mem(socket) ((socket)->private[3]) +#define rl_config(socket) ((socket)->private[4]) /* * Magic Ricoh initialization code.. Save state at @@ -128,9 +135,17 @@ rl_ctl(socket) = config_readw(socket, RL5C4XX_16BIT_CTL); rl_io(socket) = config_readw(socket, RL5C4XX_16BIT_IO_0); rl_mem(socket) = config_readw(socket, RL5C4XX_16BIT_MEM_0); + rl_config(socket) = config_readw(socket, RL5C4XX_CONFIG); /* Set the default timings, don't trust the original values */ rl_ctl(socket) = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING; + + if(socket->dev->device < PCI_DEVICE_ID_RICOH_RL5C475) { + rl_ctl(socket) |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2; + } else { + rl_config(socket) |= RL5C4XX_CONFIG_PREFETCH; + } + return 0; } @@ -142,6 +157,8 @@ config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket)); config_writew(socket, RL5C4XX_16BIT_IO_0, rl_io(socket)); config_writew(socket, RL5C4XX_16BIT_MEM_0, rl_mem(socket)); + config_writew(socket, RL5C4XX_CONFIG, rl_config(socket)); + return 0; } diff -Nru a/drivers/pcmcia/sa1100_adsbitsy.c b/drivers/pcmcia/sa1100_adsbitsy.c --- a/drivers/pcmcia/sa1100_adsbitsy.c Tue Oct 15 20:29:23 2002 +++ b/drivers/pcmcia/sa1100_adsbitsy.c Tue Oct 15 20:29:23 2002 @@ -84,14 +84,14 @@ } static struct pcmcia_low_level adsbitsy_pcmcia_ops = { - init: adsbitsy_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: adsbitsy_pcmcia_configure_socket, + .init = adsbitsy_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = adsbitsy_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_adsbitsy_init(void) diff -Nru a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c --- a/drivers/pcmcia/sa1100_assabet.c Tue Oct 15 20:29:20 2002 +++ b/drivers/pcmcia/sa1100_assabet.c Tue Oct 15 20:29:20 2002 @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -192,14 +193,14 @@ } static struct pcmcia_low_level assabet_pcmcia_ops = { - init: assabet_pcmcia_init, - shutdown: assabet_pcmcia_shutdown, - socket_state: assabet_pcmcia_socket_state, - get_irq_info: assabet_pcmcia_get_irq_info, - configure_socket: assabet_pcmcia_configure_socket, + .init = assabet_pcmcia_init, + .shutdown = assabet_pcmcia_shutdown, + .socket_state = assabet_pcmcia_socket_state, + .get_irq_info = assabet_pcmcia_get_irq_info, + .configure_socket = assabet_pcmcia_configure_socket, - socket_init: assabet_pcmcia_socket_init, - socket_suspend: assabet_pcmcia_socket_suspend, + .socket_init = assabet_pcmcia_socket_init, + .socket_suspend = assabet_pcmcia_socket_suspend, }; int __init pcmcia_assabet_init(void) diff -Nru a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c --- a/drivers/pcmcia/sa1100_badge4.c Tue Oct 15 20:29:12 2002 +++ b/drivers/pcmcia/sa1100_badge4.c Tue Oct 15 20:29:12 2002 @@ -146,14 +146,14 @@ } static struct pcmcia_low_level badge4_pcmcia_ops = { - init: badge4_pcmcia_init, - shutdown: badge4_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: badge4_pcmcia_configure_socket, + .init = badge4_pcmcia_init, + .shutdown = badge4_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = badge4_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_badge4_init(void) diff -Nru a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c --- a/drivers/pcmcia/sa1100_cerf.c Tue Oct 15 20:29:21 2002 +++ b/drivers/pcmcia/sa1100_cerf.c Tue Oct 15 20:29:21 2002 @@ -11,6 +11,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -160,14 +161,14 @@ } static struct pcmcia_low_level cerf_pcmcia_ops = { - init: cerf_pcmcia_init, - shutdown: cerf_pcmcia_shutdown, - socket_state: cerf_pcmcia_socket_state, - get_irq_info: cerf_pcmcia_get_irq_info, - configure_socket: cerf_pcmcia_configure_socket, + .init = cerf_pcmcia_init, + .shutdown = cerf_pcmcia_shutdown, + .socket_state = cerf_pcmcia_socket_state, + .get_irq_info = cerf_pcmcia_get_irq_info, + .configure_socket = cerf_pcmcia_configure_socket, - socket_init: cerf_pcmcia_socket_init, - socket_suspend: cerf_pcmcia_socket_suspend, + .socket_init = cerf_pcmcia_socket_init, + .socket_suspend = cerf_pcmcia_socket_suspend, }; int __init pcmcia_cerf_init(void) diff -Nru a/drivers/pcmcia/sa1100_flexanet.c b/drivers/pcmcia/sa1100_flexanet.c --- a/drivers/pcmcia/sa1100_flexanet.c Tue Oct 15 20:29:17 2002 +++ b/drivers/pcmcia/sa1100_flexanet.c Tue Oct 15 20:29:17 2002 @@ -11,6 +11,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -221,14 +222,14 @@ * */ static struct pcmcia_low_level flexanet_pcmcia_ops = { - init: flexanet_pcmcia_init, - shutdown: flexanet_pcmcia_shutdown, - socket_state: flexanet_pcmcia_socket_state, - get_irq_info: flexanet_pcmcia_get_irq_info, - configure_socket: flexanet_pcmcia_configure_socket, + .init = flexanet_pcmcia_init, + .shutdown = flexanet_pcmcia_shutdown, + .socket_state = flexanet_pcmcia_socket_state, + .get_irq_info = flexanet_pcmcia_get_irq_info, + .configure_socket = flexanet_pcmcia_configure_socket, - socket_init: flexanet_pcmcia_socket_init, - socket_suspend: flexanet_pcmcia_socket_suspend, + .socket_init = flexanet_pcmcia_socket_init, + .socket_suspend = flexanet_pcmcia_socket_suspend, }; int __init pcmcia_flexanet_init(void) diff -Nru a/drivers/pcmcia/sa1100_freebird.c b/drivers/pcmcia/sa1100_freebird.c --- a/drivers/pcmcia/sa1100_freebird.c Tue Oct 15 20:29:11 2002 +++ b/drivers/pcmcia/sa1100_freebird.c Tue Oct 15 20:29:11 2002 @@ -9,6 +9,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -178,14 +179,14 @@ } static struct pcmcia_low_level freebird_pcmcia_ops = { - init: freebird_pcmcia_init, - shutdown: freebird_pcmcia_shutdown, - socket_state: freebird_pcmcia_socket_state, - get_irq_info: freebird_pcmcia_get_irq_info, - configure_socket: freebird_pcmcia_configure_socket, + .init = freebird_pcmcia_init, + .shutdown = freebird_pcmcia_shutdown, + .socket_state = freebird_pcmcia_socket_state, + .get_irq_info = freebird_pcmcia_get_irq_info, + .configure_socket = freebird_pcmcia_configure_socket, - socket_init: freebird_pcmcia_socket_init, - socket_suspend: freebird_pcmcia_socket_suspend, + .socket_init = freebird_pcmcia_socket_init, + .socket_suspend = freebird_pcmcia_socket_suspend, }; int __init pcmcia_freebird_init(void) diff -Nru a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c --- a/drivers/pcmcia/sa1100_generic.c Tue Oct 15 20:29:17 2002 +++ b/drivers/pcmcia/sa1100_generic.c Tue Oct 15 20:29:17 2002 @@ -719,7 +719,7 @@ (map->flags&MAP_ATTRIB)?"ATTRIB ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); - if (map->map >= MAX_WIN){ + if (map->map >= MAX_WIN) { printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; @@ -853,19 +853,19 @@ #endif /* defined(CONFIG_PROC_FS) */ static struct pccard_operations sa1100_pcmcia_operations = { - init: sa1100_pcmcia_sock_init, - suspend: sa1100_pcmcia_suspend, - register_callback: sa1100_pcmcia_register_callback, - inquire_socket: sa1100_pcmcia_inquire_socket, - get_status: sa1100_pcmcia_get_status, - get_socket: sa1100_pcmcia_get_socket, - set_socket: sa1100_pcmcia_set_socket, - get_io_map: sa1100_pcmcia_get_io_map, - set_io_map: sa1100_pcmcia_set_io_map, - get_mem_map: sa1100_pcmcia_get_mem_map, - set_mem_map: sa1100_pcmcia_set_mem_map, + .init = sa1100_pcmcia_sock_init, + .suspend = sa1100_pcmcia_suspend, + .register_callback = sa1100_pcmcia_register_callback, + .inquire_socket = sa1100_pcmcia_inquire_socket, + .get_status = sa1100_pcmcia_get_status, + .get_socket = sa1100_pcmcia_get_socket, + .set_socket = sa1100_pcmcia_set_socket, + .get_io_map = sa1100_pcmcia_get_io_map, + .set_io_map = sa1100_pcmcia_set_io_map, + .get_mem_map = sa1100_pcmcia_get_mem_map, + .set_mem_map = sa1100_pcmcia_set_mem_map, #ifdef CONFIG_PROC_FS - proc_setup: sa1100_pcmcia_proc_setup + .proc_setup = sa1100_pcmcia_proc_setup #endif }; @@ -927,7 +927,7 @@ } static struct notifier_block sa1100_pcmcia_notifier_block = { - notifier_call: sa1100_pcmcia_notifier + .notifier_call = sa1100_pcmcia_notifier }; #endif @@ -1148,6 +1148,9 @@ #ifdef CONFIG_SA1100_GRAPHICSCLIENT pcmcia_gcplus_init(); #endif +#ifdef CONFIG_SA1100_H3600 + pcmcia_h3600_init(); +#endif #ifdef CONFIG_SA1100_PANGOLIN pcmcia_pangolin_init(); #endif @@ -1191,6 +1194,9 @@ #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT pcmcia_gcplus_exit(); +#endif +#ifdef CONFIG_SA1100_H3600 + pcmcia_h3600_exit(); #endif #ifdef CONFIG_SA1100_PANGOLIN pcmcia_pangolin_exit(); diff -Nru a/drivers/pcmcia/sa1100_graphicsclient.c b/drivers/pcmcia/sa1100_graphicsclient.c --- a/drivers/pcmcia/sa1100_graphicsclient.c Tue Oct 15 20:29:11 2002 +++ b/drivers/pcmcia/sa1100_graphicsclient.c Tue Oct 15 20:29:11 2002 @@ -17,6 +17,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -159,14 +160,14 @@ } static struct pcmcia_low_level gcplus_pcmcia_ops = { - init: gcplus_pcmcia_init, - shutdown: gcplus_pcmcia_shutdown, - socket_state: gcplus_pcmcia_socket_state, - get_irq_info: gcplus_pcmcia_get_irq_info, - configure_socket: gcplus_pcmcia_configure_socket, + .init = gcplus_pcmcia_init, + .shutdown = gcplus_pcmcia_shutdown, + .socket_state = gcplus_pcmcia_socket_state, + .get_irq_info = gcplus_pcmcia_get_irq_info, + .configure_socket = gcplus_pcmcia_configure_socket, - socket_init: gcplus_pcmcia_socket_init, - socket_suspend: gcplus_pcmcia_socket_suspend, + .socket_init = gcplus_pcmcia_socket_init, + .socket_suspend = gcplus_pcmcia_socket_suspend, }; int __init pcmcia_gcplus_init(void) diff -Nru a/drivers/pcmcia/sa1100_graphicsmaster.c b/drivers/pcmcia/sa1100_graphicsmaster.c --- a/drivers/pcmcia/sa1100_graphicsmaster.c Tue Oct 15 20:29:12 2002 +++ b/drivers/pcmcia/sa1100_graphicsmaster.c Tue Oct 15 20:29:12 2002 @@ -82,14 +82,14 @@ } static struct pcmcia_low_level graphicsmaster_pcmcia_ops = { - init: graphicsmaster_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: graphicsmaster_pcmcia_configure_socket, + .init = graphicsmaster_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = graphicsmaster_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_graphicsmaster_init(void) diff -Nru a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c --- a/drivers/pcmcia/sa1100_h3600.c Tue Oct 15 20:29:19 2002 +++ b/drivers/pcmcia/sa1100_h3600.c Tue Oct 15 20:29:19 2002 @@ -10,6 +10,9 @@ #include #include +#include +#include + #include "sa1100_generic.h" static struct irqs { @@ -185,13 +188,27 @@ } struct pcmcia_low_level h3600_pcmcia_ops = { - init: h3600_pcmcia_init, - shutdown: h3600_pcmcia_shutdown, - socket_state: h3600_pcmcia_socket_state, - get_irq_info: h3600_pcmcia_get_irq_info, - configure_socket: h3600_pcmcia_configure_socket, + .init = h3600_pcmcia_init, + .shutdown = h3600_pcmcia_shutdown, + .socket_state = h3600_pcmcia_socket_state, + .get_irq_info = h3600_pcmcia_get_irq_info, + .configure_socket = h3600_pcmcia_configure_socket, - socket_init: h3600_pcmcia_socket_init, - socket_suspend: h3600_pcmcia_socket_suspend, + .socket_init = h3600_pcmcia_socket_init, + .socket_suspend = h3600_pcmcia_socket_suspend, }; +int __init pcmcia_h3600_init(void) +{ + int ret = -ENODEV; + + if (machine_is_h3600()) + ret = sa1100_register_pcmcia(&h3600_pcmcia_ops); + + return ret; +} + +void __exit pcmcia_h3600_exit(void) +{ + sa1100_unregister_pcmcia(&h3600_pcmcia_ops); +} diff -Nru a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c --- a/drivers/pcmcia/sa1100_jornada720.c Tue Oct 15 20:29:16 2002 +++ b/drivers/pcmcia/sa1100_jornada720.c Tue Oct 15 20:29:16 2002 @@ -97,14 +97,14 @@ } static struct pcmcia_low_level jornada720_pcmcia_ops = { - init: jornada720_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: jornada720_pcmcia_configure_socket, + .init = jornada720_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = jornada720_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_jornada720_init(void) diff -Nru a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c --- a/drivers/pcmcia/sa1100_neponset.c Tue Oct 15 20:29:21 2002 +++ b/drivers/pcmcia/sa1100_neponset.c Tue Oct 15 20:29:21 2002 @@ -127,14 +127,14 @@ } static struct pcmcia_low_level neponset_pcmcia_ops = { - init: neponset_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: neponset_pcmcia_configure_socket, + .init = neponset_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = neponset_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_neponset_init(void) diff -Nru a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c --- a/drivers/pcmcia/sa1100_pangolin.c Tue Oct 15 20:29:12 2002 +++ b/drivers/pcmcia/sa1100_pangolin.c Tue Oct 15 20:29:12 2002 @@ -10,6 +10,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -159,13 +160,13 @@ } static struct pcmcia_low_level pangolin_pcmcia_ops = { - init: pangolin_pcmcia_init, - shutdown: pangolin_pcmcia_shutdown, - socket_state: pangolin_pcmcia_socket_state, - get_irq_info: pangolin_pcmcia_get_irq_info, - configure_socket: pangolin_pcmcia_configure_socket, + .init = pangolin_pcmcia_init, + .shutdown = pangolin_pcmcia_shutdown, + .socket_state = pangolin_pcmcia_socket_state, + .get_irq_info = pangolin_pcmcia_get_irq_info, + .configure_socket = pangolin_pcmcia_configure_socket, - socket_init: pangolin_pcmcia_socket_init, + .socket_init = pangolin_pcmcia_socket_init, socket_suspend, pangolin_pcmcia_socket_suspend, }; diff -Nru a/drivers/pcmcia/sa1100_pfs168.c b/drivers/pcmcia/sa1100_pfs168.c --- a/drivers/pcmcia/sa1100_pfs168.c Tue Oct 15 20:29:16 2002 +++ b/drivers/pcmcia/sa1100_pfs168.c Tue Oct 15 20:29:16 2002 @@ -119,14 +119,14 @@ } static struct pcmcia_low_level pfs168_pcmcia_ops = { - init: pfs168_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: pfs168_pcmcia_configure_socket, + .init = pfs168_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = pfs168_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_pfs168_init(void) diff -Nru a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c --- a/drivers/pcmcia/sa1100_shannon.c Tue Oct 15 20:29:21 2002 +++ b/drivers/pcmcia/sa1100_shannon.c Tue Oct 15 20:29:21 2002 @@ -9,6 +9,7 @@ #include #include +#include #include #include #include "sa1100_generic.h" @@ -151,14 +152,14 @@ } static struct pcmcia_low_level shannon_pcmcia_ops = { - init: shannon_pcmcia_init, - shutdown: shannon_pcmcia_shutdown, - socket_state: shannon_pcmcia_socket_state, - get_irq_info: shannon_pcmcia_get_irq_info, - configure_socket: shannon_pcmcia_configure_socket, + .init = shannon_pcmcia_init, + .shutdown = shannon_pcmcia_shutdown, + .socket_state = shannon_pcmcia_socket_state, + .get_irq_info = shannon_pcmcia_get_irq_info, + .configure_socket = shannon_pcmcia_configure_socket, - socket_init: shannon_pcmcia_socket_init, - socket_suspend: shannon_pcmcia_socket_suspend, + .socket_init = shannon_pcmcia_socket_init, + .socket_suspend = shannon_pcmcia_socket_suspend, }; int __init pcmcia_shannon_init(void) diff -Nru a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c --- a/drivers/pcmcia/sa1100_simpad.c Tue Oct 15 20:29:23 2002 +++ b/drivers/pcmcia/sa1100_simpad.c Tue Oct 15 20:29:23 2002 @@ -9,6 +9,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -158,14 +159,14 @@ } static struct pcmcia_low_level simpad_pcmcia_ops = { - init: simpad_pcmcia_init, - shutdown: simpad_pcmcia_shutdown, - socket_state: simpad_pcmcia_socket_state, - get_irq_info: simpad_pcmcia_get_irq_info, - configure_socket: simpad_pcmcia_configure_socket, + .init = simpad_pcmcia_init, + .shutdown = simpad_pcmcia_shutdown, + .socket_state = simpad_pcmcia_socket_state, + .get_irq_info = simpad_pcmcia_get_irq_info, + .configure_socket = simpad_pcmcia_configure_socket, - socket_init: simpad_pcmcia_socket_init, - socket_suspend: simpad_pcmcia_socket_suspend, + .socket_init = simpad_pcmcia_socket_init, + .socket_suspend = simpad_pcmcia_socket_suspend, }; int __init pcmcia_simpad_init(void) diff -Nru a/drivers/pcmcia/sa1100_stork.c b/drivers/pcmcia/sa1100_stork.c --- a/drivers/pcmcia/sa1100_stork.c Tue Oct 15 20:29:17 2002 +++ b/drivers/pcmcia/sa1100_stork.c Tue Oct 15 20:29:17 2002 @@ -25,6 +25,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -227,14 +228,14 @@ } static struct pcmcia_low_level stork_pcmcia_ops = { - init: stork_pcmcia_init, - shutdown: stork_pcmcia_shutdown, - socket_state: stork_pcmcia_socket_state, - get_irq_info: stork_pcmcia_get_irq_info, - configure_socket: stork_pcmcia_configure_socket, + .init = stork_pcmcia_init, + .shutdown = stork_pcmcia_shutdown, + .socket_state = stork_pcmcia_socket_state, + .get_irq_info = stork_pcmcia_get_irq_info, + .configure_socket = stork_pcmcia_configure_socket, - socket_init: stork_pcmcia_socket_init, - socket_suspend: stork_pcmcia_socket_suspend, + .socket_init = stork_pcmcia_socket_init, + .socket_suspend = stork_pcmcia_socket_suspend, }; int __init pcmcia_stork_init(void) diff -Nru a/drivers/pcmcia/sa1100_system3.c b/drivers/pcmcia/sa1100_system3.c --- a/drivers/pcmcia/sa1100_system3.c Tue Oct 15 20:29:23 2002 +++ b/drivers/pcmcia/sa1100_system3.c Tue Oct 15 20:29:23 2002 @@ -106,14 +106,14 @@ } struct pcmcia_low_level system3_pcmcia_ops = { - init: system3_pcmcia_init, - shutdown: system3_pcmcia_shutdown, - socket_state: system3_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: system3_pcmcia_configure_socket, + .init = system3_pcmcia_init, + .shutdown = system3_pcmcia_shutdown, + .socket_state = system3_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = system3_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_system3_init(void) diff -Nru a/drivers/pcmcia/sa1100_trizeps.c b/drivers/pcmcia/sa1100_trizeps.c --- a/drivers/pcmcia/sa1100_trizeps.c Tue Oct 15 20:29:17 2002 +++ b/drivers/pcmcia/sa1100_trizeps.c Tue Oct 15 20:29:17 2002 @@ -14,6 +14,7 @@ #include #include // included trizeps.h +#include #include #include #include "sa1100_generic.h" @@ -191,13 +192,13 @@ * ******************************************************/ struct pcmcia_low_level trizeps_pcmcia_ops = { - init: trizeps_pcmcia_init, - shutdown: trizeps_pcmcia_shutdown, - socket_state: trizeps_pcmcia_socket_state, - get_irq_info: trizeps_pcmcia_get_irq_info, - configure_socket: trizeps_pcmcia_configure_socket, - socket_init: trizeps_pcmcia_socket_init, - socket_suspend: trizeps_pcmcia_socket_suspend, + .init = trizeps_pcmcia_init, + .shutdown = trizeps_pcmcia_shutdown, + .socket_state = trizeps_pcmcia_socket_state, + .get_irq_info = trizeps_pcmcia_get_irq_info, + .configure_socket = trizeps_pcmcia_configure_socket, + .socket_init = trizeps_pcmcia_socket_init, + .socket_suspend = trizeps_pcmcia_socket_suspend, }; int __init pcmcia_trizeps_init(void) diff -Nru a/drivers/pcmcia/sa1100_xp860.c b/drivers/pcmcia/sa1100_xp860.c --- a/drivers/pcmcia/sa1100_xp860.c Tue Oct 15 20:29:16 2002 +++ b/drivers/pcmcia/sa1100_xp860.c Tue Oct 15 20:29:16 2002 @@ -132,14 +132,14 @@ } static struct pcmcia_low_level xp860_pcmcia_ops = { - init: xp860_pcmcia_init, - shutdown: sa1111_pcmcia_shutdown, - socket_state: sa1111_pcmcia_socket_state, - get_irq_info: sa1111_pcmcia_get_irq_info, - configure_socket: xp860_pcmcia_configure_socket, + .init = xp860_pcmcia_init, + .shutdown = sa1111_pcmcia_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .get_irq_info = sa1111_pcmcia_get_irq_info, + .configure_socket = xp860_pcmcia_configure_socket, - socket_init: sa1111_pcmcia_socket_init, - socket_suspend: sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_xp860_init(void) diff -Nru a/drivers/pcmcia/sa1100_yopy.c b/drivers/pcmcia/sa1100_yopy.c --- a/drivers/pcmcia/sa1100_yopy.c Tue Oct 15 20:29:20 2002 +++ b/drivers/pcmcia/sa1100_yopy.c Tue Oct 15 20:29:20 2002 @@ -9,6 +9,7 @@ #include #include +#include #include #include "sa1100_generic.h" @@ -160,14 +161,14 @@ } static struct pcmcia_low_level yopy_pcmcia_ops = { - init: yopy_pcmcia_init, - shutdown: yopy_pcmcia_shutdown, - socket_state: yopy_pcmcia_socket_state, - get_irq_info: yopy_pcmcia_get_irq_info, - configure_socket: yopy_pcmcia_configure_socket, + .init = yopy_pcmcia_init, + .shutdown = yopy_pcmcia_shutdown, + .socket_state = yopy_pcmcia_socket_state, + .get_irq_info = yopy_pcmcia_get_irq_info, + .configure_socket = yopy_pcmcia_configure_socket, - socket_init: yopy_pcmcia_socket_init, - socket_suspend: yopy_pcmcia_socket_suspend, + .socket_init = yopy_pcmcia_socket_init, + .socket_suspend = yopy_pcmcia_socket_suspend, }; int __init pcmcia_yopy_init(void) diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c --- a/drivers/s390/block/dasd.c Tue Oct 15 20:29:16 2002 +++ b/drivers/s390/block/dasd.c Tue Oct 15 20:29:16 2002 @@ -2110,8 +2110,6 @@ dasd_device_t *device; int rc; - if ((!inp) || kdev_none(inp->i_rdev)) - return -EINVAL; if (dasd_probeonly) { MESSAGE(KERN_INFO, "No access to device (%d:%d) due to probeonly mode", @@ -2154,8 +2152,6 @@ dasd_devmap_t *devmap; dasd_device_t *device; - if ((!inp) || kdev_none(inp->i_rdev)) - return -EINVAL; devmap = dasd_devmap_from_kdev(inp->i_rdev); device = (devmap != NULL) ? dasd_get_device(devmap) : ERR_PTR(-ENODEV); diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c --- a/drivers/s390/block/dasd_genhd.c Tue Oct 15 20:29:20 2002 +++ b/drivers/s390/block/dasd_genhd.c Tue Oct 15 20:29:20 2002 @@ -190,14 +190,13 @@ } } - gdp = alloc_disk(); + gdp = alloc_disk(1 << DASD_PARTN_BITS); if (!gdp) return ERR_PTR(-ENOMEM); /* Initialize gendisk structure. */ gdp->major = mi->major; gdp->first_minor = index << DASD_PARTN_BITS; - gdp->minor_shift = DASD_PARTN_BITS; gdp->fops = &dasd_device_operations; /* diff -Nru a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c --- a/drivers/s390/block/xpram.c Tue Oct 15 20:29:19 2002 +++ b/drivers/s390/block/xpram.c Tue Oct 15 20:29:19 2002 @@ -324,24 +324,12 @@ return 0; } -/* - * The file operations - */ -static int xpram_open (struct inode *inode, struct file *filp) -{ - if (minor(inode->i_rdev) >= xpram_devs) - return -ENODEV; - return 0; -} - static int xpram_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct hd_geometry *geo; unsigned long size; int idx = minor(inode->i_rdev); - if (idx >= xpram_devs) - return -ENODEV; if (cmd != HDIO_GETGEO) return -EINVAL; /* @@ -350,8 +338,6 @@ * whatever cylinders. Tell also that data starts at sector. 4. */ geo = (struct hd_geometry *) arg; - if (geo == NULL) - return -EINVAL; size = (xpram_pages * 8) & ~0x3f; put_user(size >> 6, &geo->cylinders); put_user(4, &geo->heads); @@ -364,7 +350,6 @@ { owner: THIS_MODULE, ioctl: xpram_ioctl, - open: xpram_open, }; /* @@ -441,7 +426,7 @@ int i, rc = -ENOMEM; for (i = 0; i < xpram_devs; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); if (!disk) goto out; xpram_disks[i] = disk; @@ -481,7 +466,6 @@ offset += xpram_devices[i].size; disk->major = XPRAM_MAJOR; disk->first_minor = i; - disk->minor_shift = 0; disk->fops = &xpram_devops; sprintf(disk->disk_name, "slram%d", i); set_capacity(disk, xpram_sizes[i] << 1); diff -Nru a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c --- a/drivers/sbus/char/jsflash.c Tue Oct 15 20:29:16 2002 +++ b/drivers/sbus/char/jsflash.c Tue Oct 15 20:29:16 2002 @@ -104,7 +104,6 @@ struct jsfd_part { unsigned long dbase; unsigned long dsize; - int refcnt; }; struct jsflash { @@ -454,54 +453,12 @@ return 0; /* XXX What security? */ } -static int jsfd_open(struct inode *inode, struct file *file) -{ - struct jsfd_part *jdp; - int dev; - - if (!inode) - return -EINVAL; - dev = MINOR(inode->i_rdev); - if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { - printk(KERN_ALERT "jsfd_open: illegal minor %d\n", dev); - return -ENODEV; - } - - jdp = &jsf0.dv[dev]; - jdp->refcnt++; - - return 0; -} - static int jsf_release(struct inode *inode, struct file *file) { jsf0.busy = 0; return 0; } -static int jsfd_release(struct inode *inode, struct file *file) -{ - struct jsfd_part *jdp; - int dev; - - if (!inode) - return -ENODEV; - dev = MINOR(inode->i_rdev); - if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) { - printk(KERN_ALERT "jsfd_release: illegal minor %d\n", dev); - return -ENODEV; - } - - jdp = &jsf0.dv[dev]; - if (jdp->refcnt <= 0) { - printk(KERN_ALERT "jsfd_release: bad ref on minor %d\n", dev); - } else { - --jdp->refcnt; - } - /* N.B. Doesn't lo->file need an fput?? */ - return 0; -} - static struct file_operations jsf_fops = { .owner = THIS_MODULE, .llseek = jsf_lseek, @@ -517,8 +474,6 @@ static struct block_device_operations jsfd_fops = { .owner = THIS_MODULE, - .open = jsfd_open, - .release = jsfd_release, }; static int jsflash_init(void) @@ -622,7 +577,7 @@ err = -ENOMEM; for (i = 0; i < JSF_MAX; i++) { - struct gendisk *disk = alloc_disk(); + struct gendisk *disk = alloc_disk(1); if (!disk) goto out; jsfd_disk[i] = disk; @@ -642,13 +597,10 @@ jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */ jdp = &jsf->dv[i&JSF_PART_MASK]; - jdp->refcnt = 0; - disk->major = JSFD_MAJOR; disk->first_minor = i; sprintf(disk->disk_name, "jsfd%d", i); disk->fops = &jsfd_fops; - disk->minor_shift = 0; set_capacity(disk, jdp->dsize >> 9); add_disk(disk); set_device_ro(MKDEV(JSFD_MAJOR, i), 1); diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c --- a/drivers/scsi/BusLogic.c Tue Oct 15 20:29:21 2002 +++ b/drivers/scsi/BusLogic.c Tue Oct 15 20:29:21 2002 @@ -2604,21 +2604,21 @@ through Host Adapter. */ -static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T +/*static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T *HostAdapter) { int TargetID; - /* +*/ /* Inhibit the Target Device Inquiry and Reporting if requested. */ - if (BusLogic_MultiMasterHostAdapterP(HostAdapter) && +/* if (BusLogic_MultiMasterHostAdapterP(HostAdapter) && HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) return; - /* +*/ /* Report on the Target Devices found. */ - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) +/* for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID]; if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported) @@ -2674,7 +2674,7 @@ } } } - +*/ /* BusLogic_InitializeHostStructure initializes the fields in the SCSI Host @@ -2700,6 +2700,49 @@ Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth; } +/* + BusLogic_SlaveAttach will actually set the queue depth on individual + scsi devices as they are permanently added to the device chain. We + shamelessly rip off the SelectQueueDepths code to make this work mostly + like it used to. Since we don't get called once at the end of the scan + but instead get called for each device, we have to do things a bit + differently. +*/ +int BusLogic_SlaveAttach(SCSI_Device_T *Device) +{ + BusLogic_HostAdapter_T *HostAdapter = + (BusLogic_HostAdapter_T *) Device->host->hostdata; + int TargetID = Device->id; + int QueueDepth = HostAdapter->QueueDepth[TargetID]; + + if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && + (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) + { + if (QueueDepth == 0) + QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth); + } + else + { + HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); + QueueDepth = HostAdapter->UntaggedQueueDepth; + HostAdapter->QueueDepth[TargetID] = QueueDepth; + scsi_adjust_queue_depth(Device, 0, QueueDepth); + } + QueueDepth = 0; + for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) + if (HostAdapter->TargetFlags[TargetID].TargetExists) + { + QueueDepth += HostAdapter->QueueDepth[TargetID]; + } + if (QueueDepth > HostAdapter->AllocatedCCBs) + BusLogic_CreateAdditionalCCBs(HostAdapter, + QueueDepth + - HostAdapter->AllocatedCCBs, + false); + return 0; +} /* BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based @@ -2709,7 +2752,7 @@ since all the Target Devices have now been probed. */ -static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host, +/* static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host, SCSI_Device_T *DeviceList) { BusLogic_HostAdapter_T *HostAdapter = @@ -2764,8 +2807,8 @@ for (Device = DeviceList; Device != NULL; Device = Device->next) if (Device->host == Host) Device->queue_depth = HostAdapter->QueueDepth[Device->id]; - /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */ - AllocatedQueueDepth += HostAdapter->TargetDeviceCount; +*/ /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */ +/* AllocatedQueueDepth += HostAdapter->TargetDeviceCount; if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth) AllocatedQueueDepth = HostAdapter->DriverQueueDepth; BusLogic_CreateAdditionalCCBs(HostAdapter, @@ -2778,7 +2821,7 @@ HostAdapter = HostAdapter->Next) BusLogic_ReportTargetDeviceInfo(HostAdapter); } - +*/ /* BusLogic_DetectHostAdapter probes for BusLogic Host Adapters at the standard @@ -2881,7 +2924,10 @@ memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T)); HostAdapter->SCSI_Host = Host; HostAdapter->HostNumber = Host->host_no; + /* + * This function is deprecated Host->select_queue_depths = BusLogic_SelectQueueDepths; + */ /* Add Host Adapter to the end of the list of registered BusLogic Host Adapters. diff -Nru a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h --- a/drivers/scsi/BusLogic.h Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/BusLogic.h Tue Oct 15 20:29:16 2002 @@ -60,6 +60,7 @@ extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, struct block_device *, int *); extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int); +extern int BusLogic_SlaveAttach(SCSI_Device_T *); /* @@ -76,6 +77,7 @@ queuecommand: BusLogic_QueueCommand, /* Queue Command Function */ \ abort: BusLogic_AbortCommand, /* Abort Command Function */ \ reset: BusLogic_ResetCommand, /* Reset Command Function */ \ + slave_attach: BusLogic_SlaveAttach, /* Configure a SCSI_Device*/ \ bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \ unchecked_isa_dma: 1, /* Default Initial Value */ \ max_sectors: 128, /* I/O queue len limit */ \ diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c --- a/drivers/scsi/NCR5380.c Tue Oct 15 20:29:14 2002 +++ b/drivers/scsi/NCR5380.c Tue Oct 15 20:29:14 2002 @@ -1068,7 +1068,7 @@ * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * - * Locks: io_request lock held by caller. Called functions drop and + * Locks: host lock taken by caller. Called functions drop and * retake this lock. Called functions take dma lock. */ @@ -1080,6 +1080,7 @@ struct Scsi_Host *instance = cmd->host; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp; + unsigned long flags; #if (NDEBUG & NDEBUG_NO_WRITE) switch (cmd->cmnd[0]) { @@ -1092,6 +1093,7 @@ } #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ + spin_lock_irqsave(instance->host_lock, flags); #ifdef NCR5380_STATS switch (cmd->cmnd[0]) { case WRITE: @@ -1139,8 +1141,8 @@ dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); /* Run the coroutine if it isn't already running. */ + spin_unlock_irqrestore(instance->host_lock, flags); - /* FIMXE: drop any locks here */ run_main(); return 0; } @@ -1892,7 +1894,6 @@ * back into sane shape. * * Locks: caller holds queue lock - * FIXME: sort this out and get new_eh running */ static void do_reset(struct Scsi_Host *host) { @@ -2841,7 +2842,7 @@ * a problem, we could implement longjmp() / setjmp(), setjmp() * called where the loop started in NCR5380_main(). * - * Locks: io_request_lock held by caller + * Locks: host lock taken by function */ #ifndef NCR5380_abort @@ -2850,8 +2851,11 @@ int NCR5380_abort(Scsi_Cmnd * cmd) { NCR5380_local_declare(); struct Scsi_Host *instance = cmd->host; + unsigned long flags; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; Scsi_Cmnd *tmp, **prev; + + spin_lock_irqsave(instance->host_lock, flags); printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no); print_Scsi_Cmnd(cmd); @@ -2895,6 +2899,7 @@ * aborted flag and get back into our main loop. */ + spin_unlock_irqrestore(instance->host_lock, flags); return 0; } #endif @@ -2915,6 +2920,7 @@ tmp->result = DID_ABORT << 16; dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no)); tmp->done(tmp); + spin_unlock_irqrestore(instance->host_lock, flags); return SUCCESS; } #if (NDEBUG & NDEBUG_ABORT) @@ -2936,6 +2942,7 @@ if (hostdata->connected) { dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no)); + spin_unlock_irqrestore(instance->host_lock, flags); return FAILED; } /* @@ -2980,6 +2987,7 @@ tmp->host_scribble = NULL; tmp->result = DID_ABORT << 16; tmp->done(tmp); + spin_unlock_irqrestore(instance->host_lock, flags); return SUCCESS; } } @@ -2992,7 +3000,9 @@ * so we won't panic, but we will notify the user in case something really * broke. */ - printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n" " before abortion\n", instance->host_no); + spin_unlock_irqrestore(instance->host_lock, flags); + printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n" + " before abortion\n", instance->host_no); return FAILED; } @@ -3004,19 +3014,22 @@ * * Returns : SUCCESS * - * Locks: io_request_lock held by caller + * Locks: host lock taken by function */ #ifndef NCR5380_bus_reset static #endif int NCR5380_bus_reset(Scsi_Cmnd * cmd) { + unsigned long flags; + struct Scsi_Host *instance = cmd->host; NCR5380_local_declare(); NCR5380_setup(cmd->host); + spin_lock_irqsave(instance->host_lock, flags); NCR5380_print_status(cmd->host); do_reset(cmd->host); - + spin_unlock_irqrestore(instance->host_lock, flags); return SUCCESS; } diff -Nru a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile --- a/drivers/scsi/aacraid/Makefile Tue Oct 15 20:29:20 2002 +++ b/drivers/scsi/aacraid/Makefile Tue Oct 15 20:29:20 2002 @@ -1,8 +1,10 @@ # Adaptec aacraid - + obj-$(CONFIG_SCSI_AACRAID) := aacraid.o aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ dpcsup.o rx.o sa.o + +EXTRA_CFLAGS := -Idrivers/scsi include $(TOPDIR)/Rules.make diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/aacraid/linit.c Tue Oct 15 20:29:16 2002 @@ -128,7 +128,7 @@ static int aac_eh_bus_reset(Scsi_Cmnd* cmd); static int aac_eh_reset(Scsi_Cmnd* cmd); -static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *); +static int aac_slave_attach(Scsi_Device *); /** * aac_detect - Probe for aacraid cards @@ -227,12 +227,6 @@ * value returned as aac->id. */ host_ptr->unique_id = aac_count - 1; - /* - * This function is called after the device list has - * been built to find the tagged queueing depth - * supported for each device. - */ - host_ptr->select_queue_depths = aac_queuedepth; aac = (struct aac_dev *)host_ptr->hostdata; /* attach a pointer back to Scsi_Host */ aac->scsi_host_ptr = host_ptr; @@ -520,31 +514,25 @@ } /** - * aac_queuedepth - compute queue depths - * @host: SCSI host in question - * @dev: SCSI device we are considering + * aac_slave_attach - do device specific setup + * @dev: SCSI device we are attaching * - * Selects queue depths for each target device based on the host adapter's - * total capacity and the queue depth supported by the target device. - * A queue depth of one automatically disables tagged queueing. + * Currently, all we do is set the queue depth on the device. */ -static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev ) +static int aac_slave_attach(Scsi_Device * dev ) { - Scsi_Device * dptr; - dprintk((KERN_DEBUG "aac_queuedepth.\n")); - dprintk((KERN_DEBUG "Device # Q Depth Online\n")); - dprintk((KERN_DEBUG "---------------------------\n")); - for(dptr = dev; dptr != NULL; dptr = dptr->next) - { - if(dptr->host == host) - { - dptr->queue_depth = 10; - dprintk((KERN_DEBUG " %2d %d %d\n", - dptr->id, dptr->queue_depth, dptr->online)); - } - } + if(dev->tagged_supported) + scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, 128); + else + scsi_adjust_queue_depth(dev, 0, 1); + + dprintk((KERN_DEBUG "(scsi%d:%d:%d:%d) Tagged Queue depth %2d, " + "%s\n", dev->host->host_no, dev->channel, + dev->id, dev->lun, dev->new_queue_depth, + dev->online ? "OnLine" : "OffLine")); + return 0; } @@ -693,6 +681,7 @@ ioctl: aac_ioctl, queuecommand: aac_queuecommand, bios_param: aac_biosparm, + slave_attach: aac_slave_attach, can_queue: AAC_NUM_IO_FIB, this_id: 16, sg_tablesize: 16, diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c --- a/drivers/scsi/advansys.c Tue Oct 15 20:29:15 2002 +++ b/drivers/scsi/advansys.c Tue Oct 15 20:29:15 2002 @@ -673,6 +673,10 @@ 3.3GJ (4/15/02): 1. hacks for lk 2.5 series (D. Gilbert) + 3.3GJD (10/14/02): + 1. change select_queue_depths to slave_attach + 2. make cmd_per_lun be sane again + I. Known Problems/Fix List (XXX) 1. Need to add memory mapping workaround. Test the memory mapping. @@ -4208,8 +4212,7 @@ */ STATIC void advansys_interrupt(int, void *, struct pt_regs *); -STATIC void advansys_select_queue_depths(struct Scsi_Host *, - Scsi_Device *); +STATIC int advansys_slave_attach(Scsi_Device *); STATIC void asc_scsi_done_list(Scsi_Cmnd *, int from_isr); STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *); @@ -5307,17 +5310,15 @@ * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level * SCSI function 'allocate_device' will panic. To allow the driver * to work as a module in these kernels set 'cmd_per_lun' to 1. - */ + * + * Note: This is wrong. cmd_per_lun should be set to the depth + * you want on untagged devices always. #ifdef MODULE + */ shp->cmd_per_lun = 1; -#else /* MODULE */ +/* #else shp->cmd_per_lun = 0; -#endif /* MODULE */ - /* - * Use the host 'select_queue_depths' function to determine - * the number of commands to queue per device. - */ - shp->select_queue_depths = advansys_select_queue_depths; +#endif */ /* * Set the maximum number of scatter-gather elements the @@ -6346,34 +6347,33 @@ * Set the number of commands to queue per device for the * specified host adapter. */ -STATIC void -advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist) +STATIC int +advansys_slave_attach(Scsi_Device *device) { - Scsi_Device *device; asc_board_t *boardp; - boardp = ASC_BOARDP(shp); + boardp = ASC_BOARDP(device->host); boardp->flags |= ASC_SELECT_QUEUE_DEPTHS; - for (device = devicelist; device != NULL; device = device->next) { - if (device->host != shp) { - continue; - } - /* - * Save a pointer to the device and set its initial/maximum - * queue depth. - */ + /* + * Save a pointer to the device and set its initial/maximum + * queue depth. Only save the pointer for a lun0 dev though. + */ + if(device->lun == 0) boardp->device[device->id] = device; + if(device->tagged_supported) { if (ASC_NARROW_BOARD(boardp)) { - device->queue_depth = - boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]; + scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, + boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]); } else { - device->queue_depth = - boardp->dvc_var.adv_dvc_var.max_dvc_qng; + scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, + boardp->dvc_var.adv_dvc_var.max_dvc_qng); } - ASC_DBG3(1, - "advansys_select_queue_depths: shp 0x%lx, id %d, depth %d\n", - (ulong) shp, device->id, device->queue_depth); + } else { + scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun); } + ASC_DBG3(1, "advansys_slave_attach: shp 0x%lx, id %d, depth %d\n", + (ulong) shp, device->id, device->queue_depth); + return 0; } /* @@ -8432,7 +8432,7 @@ continue; } len = asc_prt_line(cp, leftlen, " %X:%d", - i, boardp->device[i]->queue_depth); + i, boardp->device[i]->current_queue_depth); ASC_PRT_NEXT(); } len = asc_prt_line(cp, leftlen, "\n"); diff -Nru a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h --- a/drivers/scsi/advansys.h Tue Oct 15 20:29:23 2002 +++ b/drivers/scsi/advansys.h Tue Oct 15 20:29:23 2002 @@ -53,6 +53,7 @@ int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int advansys_reset(Scsi_Cmnd *); int advansys_biosparam(Disk *, struct block_device *, int[]); +static int advansys_slave_attach(Scsi_Device *); #ifdef CONFIG_PROC_FS #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) extern struct proc_dir_entry proc_scsi_advansys; @@ -79,6 +80,7 @@ queuecommand: advansys_queuecommand, \ eh_bus_reset_handler: advansys_reset, \ bios_param: advansys_biosparam, \ + slave_attach: advansys_slave_attach, \ /* \ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \ * must be set. The flag will be cleared in advansys_detect for non-ISA \ diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c --- a/drivers/scsi/aic7xxx/aic7xxx_linux.c Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c Tue Oct 15 20:29:16 2002 @@ -430,8 +430,7 @@ static void ahc_linux_release_sim_queue(u_long arg); static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag); static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); -static void ahc_linux_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); +static int ahc_linux_slave_attach(Scsi_Device *device); static void ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device *device); static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*, @@ -1131,7 +1130,6 @@ host->can_queue = AHC_MAX_QUEUE; host->cmd_per_lun = 2; host->sg_tablesize = AHC_NSEG; - host->select_queue_depths = ahc_linux_select_queue_depth; /* XXX No way to communicate the ID for multiple channels */ host->this_id = ahc->our_id; host->irq = ahc->platform_data->irq; @@ -1449,25 +1447,17 @@ * Sets the queue depth for each SCSI device hanging * off the input host adapter. */ -static void -ahc_linux_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) +static int +ahc_linux_slave_attach(Scsi_Device * device) { - Scsi_Device *device; struct ahc_softc *ahc; u_long flags; - int scbnum; - ahc = *((struct ahc_softc **)host->hostdata); + ahc = *((struct ahc_softc **)device->host->hostdata); ahc_lock(ahc, &flags); - scbnum = 0; - for (device = scsi_devs; device != NULL; device = device->next) { - if (device->host == host) { - ahc_linux_device_queue_depth(ahc, device); - scbnum += device->queue_depth; - } - } + ahc_linux_device_queue_depth(ahc, device); ahc_unlock(ahc, &flags); + return 0; } /* @@ -1512,7 +1502,8 @@ } } if (tags != 0) { - device->queue_depth = tags; + scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, tags); + /* device->queue_depth = tags; */ ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED); printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n", ahc->platform_data->host->host_no, device->channel + 'A', @@ -1523,8 +1514,9 @@ * us at any time even though we can only execute them * serially on the controller/device. This should remove * some latency. - */ device->queue_depth = 2; + */ + scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun); } } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h --- a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h Tue Oct 15 20:29:16 2002 @@ -80,7 +80,7 @@ eh_host_reset_handler: NULL, \ abort: NULL, \ reset: NULL, \ - slave_attach: NULL, \ + slave_attach: ahc_linux_slave_attach, \ bios_param: AIC7XXX_BIOSPARAM, \ can_queue: 253, /* max simultaneous cmds */\ this_id: -1, /* scsi id of host adapter */\ diff -Nru a/drivers/scsi/cpqfc.Readme b/drivers/scsi/cpqfc.Readme --- a/drivers/scsi/cpqfc.Readme Tue Oct 15 20:29:23 2002 +++ b/drivers/scsi/cpqfc.Readme Tue Oct 15 20:29:23 2002 @@ -7,6 +7,8 @@ SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() max of 128k bytes contiguous. +Ver 2.5.4 Oct 03, 2002 + * fixed memcpy of sense buffer in ioctl to copy the smaller defined size Ver 2.5.3 Aug 01, 2002 * fix the passthru ioctl to handle the Scsi_Cmnd->request being a pointer Ver 2.5.1 Jul 30, 2002 diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c --- a/drivers/scsi/cpqfcTSinit.c Tue Oct 15 20:29:12 2002 +++ b/drivers/scsi/cpqfcTSinit.c Tue Oct 15 20:29:12 2002 @@ -68,7 +68,7 @@ /* Embedded module documentation macros - see module.h */ MODULE_AUTHOR("Compaq Computer Corporation"); -MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.3"); +MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4"); MODULE_LICENSE("GPL"); int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags); @@ -668,7 +668,11 @@ { memcpy( vendor_cmd->sense_data, // see struct def - size=40 ScsiPassThruReq->sr_sense_buffer, - sizeof(ScsiPassThruReq->sr_sense_buffer)); + sizeof(ScsiPassThruReq->sr_sense_buffer) < + sizeof(vendor_cmd->sense_data) ? + sizeof(ScsiPassThruReq->sr_sense_buffer) : + sizeof(vendor_cmd->sense_data) + ); } SDpnt = ScsiPassThruReq->sr_device; /* upper_private_data is already freed in call_scsi_done() */ diff -Nru a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h --- a/drivers/scsi/cpqfcTSstructs.h Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/cpqfcTSstructs.h Tue Oct 15 20:29:16 2002 @@ -32,7 +32,7 @@ // don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c #define VER_MAJOR 2 #define VER_MINOR 5 -#define VER_SUBMINOR 3 +#define VER_SUBMINOR 4 // Macros for kernel (esp. SMP) tracing using a PCI analyzer // (e.g. x86). diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c Tue Oct 15 20:29:15 2002 +++ b/drivers/scsi/dpt_i2o.c Tue Oct 15 20:29:15 2002 @@ -48,7 +48,6 @@ #include #include #include /* for udelay */ -#include #include #include /* for printk */ #include @@ -356,23 +355,20 @@ } -static void adpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device * devicelist) +static int adpt_slave_attach(Scsi_Device * device) { - Scsi_Device *device; /* scsi layer per device information */ + struct Scsi_Host *host = device->host; adpt_hba* pHba; pHba = (adpt_hba *) host->hostdata[0]; - for (device = devicelist; device != NULL; device = device->next) { - if (device->host != host) { - continue; - } - if (host->can_queue) { - device->queue_depth = host->can_queue - 1; - } else { - device->queue_depth = 1; - } + if (host->can_queue && device->tagged_supported) { + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + host->can_queue - 1); + } else { + scsi_adjust_queue_depth(device, 0, 1); } + return 0; } static int adpt_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) @@ -2194,11 +2190,10 @@ host->max_id = 16; host->max_lun = 256; host->max_channel = pHba->top_scsi_channel + 1; - host->cmd_per_lun = 256; + host->cmd_per_lun = 1; host->unique_id = (uint) pHba; host->sg_tablesize = pHba->sg_tablesize; host->can_queue = pHba->post_fifo_size; - host->select_queue_depths = adpt_select_queue_depths; return 0; } diff -Nru a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h --- a/drivers/scsi/dpti.h Tue Oct 15 20:29:11 2002 +++ b/drivers/scsi/dpti.h Tue Oct 15 20:29:11 2002 @@ -43,6 +43,7 @@ static int adpt_abort(Scsi_Cmnd * cmd); static int adpt_reset(Scsi_Cmnd* cmd); static int adpt_release(struct Scsi_Host *host); +static int adpt_slave_attach(Scsi_Device *); static const char *adpt_info(struct Scsi_Host *pSHost); static int adpt_bios_param(Disk * disk, struct block_device *dev, int geom[]); @@ -90,10 +91,11 @@ eh_bus_reset_handler: adpt_bus_reset, \ eh_host_reset_handler: adpt_reset, \ bios_param: adpt_bios_param, \ + slave_attach: adpt_slave_attach, \ can_queue: MAX_TO_IOP_MESSAGES, /* max simultaneous cmds */\ this_id: 7, /* scsi id of host adapter */\ sg_tablesize: 0, /* max scatter-gather cmds */\ - cmd_per_lun: 256, /* cmds per lun (linked cmds) */\ + cmd_per_lun: 1, /* cmds per lun (linked cmds) */\ use_clustering: ENABLE_CLUSTERING, \ proc_name: "dpt_i2o" /* this is the name of our proc node*/ \ } @@ -346,7 +348,6 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba); static s32 adpt_send_nop(adpt_hba*pHba,u32 m); static void adpt_i2o_delete_hba(adpt_hba* pHba); -static void adpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device * devicelist); static void adpt_inquiry(adpt_hba* pHba); static void adpt_fail_posted_scbs(adpt_hba* pHba); static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun); diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c Tue Oct 15 20:29:20 2002 +++ b/drivers/scsi/eata.c Tue Oct 15 20:29:20 2002 @@ -750,63 +750,34 @@ static int max_queue_depth = MAX_CMD_PER_LUN; #endif -static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) { - Scsi_Device *dev; - int j, ntag = 0, nuntag = 0, tqd, utqd; +static int eata2x_slave_attach(Scsi_Device *dev) { + int j, tqd, utqd; + char *link_suffix = ""; + struct Scsi_Host *host = dev->host; j = ((struct hostdata *) host->hostdata)->board_number; - for(dev = devlist; dev; dev = dev->next) { - - if (dev->host != host) continue; - - if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) - ntag++; - else - nuntag++; - } - utqd = MAX_CMD_PER_LUN; + tqd = (host->can_queue - utqd); - tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1); - - if (tqd > max_queue_depth) tqd = max_queue_depth; - - if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN; - - for(dev = devlist; dev; dev = dev->next) { - char *tag_suffix = "", *link_suffix = ""; - - if (dev->host != host) continue; - - if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) - dev->queue_depth = tqd; + if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) { + if(!dev->tagged_supported) + scsi_adjust_queue_depth(dev, 0, tqd); else - dev->queue_depth = utqd; - - if (TLDEV(dev->type)) { - if (linked_comm && dev->queue_depth > 2) - link_suffix = ", sorted"; - else - link_suffix = ", unsorted"; - } - - if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) { - dev->tagged_queue = 1; - dev->current_tag = 1; - } - - if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue) - tag_suffix = ", soft-tagged"; - else if (dev->tagged_supported && TLDEV(dev->type)) - tag_suffix = ", tagged"; - - printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n", - BN(j), host->host_no, dev->channel, dev->id, dev->lun, - dev->queue_depth, link_suffix, tag_suffix); - } + scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); + } else { + scsi_adjust_queue_depth(dev, 0, utqd); + } - return; + if (!dev->simple_tags && dev->new_queue_depth > 2) + link_suffix = ", sorted"; + else if (dev->simple_tags) + link_suffix = ", unsorted"; + + printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s.\n", + BN(j), host->host_no, dev->channel, dev->id, dev->lun, + dev->new_queue_depth, link_suffix); + return 0; } static inline int wait_on_busy(unsigned long iobase, unsigned int loop) { @@ -1071,7 +1042,6 @@ sh[j]->this_id = (ushort) info.host_addr[3]; sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size); sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; - sh[j]->select_queue_depths = select_queue_depths; memset(HD(j), 0, sizeof(struct hostdata)); HD(j)->subversion = subversion; HD(j)->protocol_rev = protocol_rev; @@ -1542,7 +1512,7 @@ /* Map DMA buffers and SG list */ map_dma(i, j); - if (SCpnt->device->tagged_queue) { + if (SCpnt->device->simple_tags) { if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] || HD(j)->target_to[SCpnt->target][SCpnt->channel]) @@ -1560,8 +1530,7 @@ cpp->mess[1] = SCpnt->device->current_tag++; } - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) { + if (SCpnt->device->new_queue_depth > 2 && !SCpnt->device->simple_tags) { HD(j)->cp_stat[i] = READY; flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE); return 0; @@ -2071,7 +2040,7 @@ sync_dma(i, j); - if (linked_comm && SCpnt->device->queue_depth > 2 + if (linked_comm && SCpnt->device->new_queue_depth > 2 && TLDEV(SCpnt->device->type)) flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE); diff -Nru a/drivers/scsi/eata.h b/drivers/scsi/eata.h --- a/drivers/scsi/eata.h Tue Oct 15 20:29:12 2002 +++ b/drivers/scsi/eata.h Tue Oct 15 20:29:12 2002 @@ -12,6 +12,7 @@ int eata2x_abort(Scsi_Cmnd *); int eata2x_reset(Scsi_Cmnd *); int eata2x_biosparam(Disk *, struct block_device *, int *); +static int eata2x_slave_attach(Scsi_Device *); #define EATA_VERSION "7.22.00" @@ -27,6 +28,7 @@ eh_bus_reset_handler: NULL, \ eh_host_reset_handler: eata2x_reset, \ bios_param: eata2x_biosparam, \ + slave_attach: eata2x_slave_attach, \ this_id: 7, \ unchecked_isa_dma: 1, \ use_clustering: ENABLE_CLUSTERING, \ diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c --- a/drivers/scsi/esp.c Tue Oct 15 20:29:23 2002 +++ b/drivers/scsi/esp.c Tue Oct 15 20:29:23 2002 @@ -1576,7 +1576,6 @@ memset(esp_dev, 0, sizeof(struct esp_device)); SDptr->hostdata = esp_dev; } - } esp->snip = 0; esp->msgout_len = 0; @@ -3589,7 +3588,7 @@ Scsi_Cmnd *SCptr, struct esp_device *esp_dev) { - if (esp_dev->sync || SCptr->SDptr->borken) { + if (esp_dev->sync || SCptr->device->borken) { /* sorry, no can do */ ESPSDTR(("forcing to async, ")); build_sync_nego_msg(esp, 0, 0); @@ -3811,7 +3810,7 @@ /* Regardless, next try for sync transfers. */ build_sync_nego_msg(esp, esp->sync_defp, 15); - espo_dev->sync = 1; + esp_dev->sync = 1; esp->snip = 1; message_out = EXTENDED_MESSAGE; } diff -Nru a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c --- a/drivers/scsi/fcal.c Tue Oct 15 20:29:12 2002 +++ b/drivers/scsi/fcal.c Tue Oct 15 20:29:12 2002 @@ -70,17 +70,21 @@ static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); -static void fcal_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) +int fcal_slave_attach(Scsi_Device *device) { - Scsi_Device *device; + int depth_to_use; - for (device = devlist; device; device = device->next) { - if (device->host != host) continue; - if (device->tagged_supported) - device->queue_depth = /* 254 */ 8; - else - device->queue_depth = 2; - } + if (device->tagged_supported) + depth_to_use = /* 254 */ 8; + else + depth_to_use = 2; + + scsi_adjust_queue_depth(device, + (device->tagged_supported ? + MSG_SIMPLE_TAG : 0), + depth_to_use); + + return 0; } /* Detect all FC Arbitrated Loops attached to the machine. @@ -165,7 +169,6 @@ #ifdef __sparc_v9__ host->unchecked_isa_dma = 1; #endif - host->select_queue_depths = fcal_select_queue_depths; fc->channels = 1; fc->targets = 127; diff -Nru a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h --- a/drivers/scsi/fcal.h Tue Oct 15 20:29:11 2002 +++ b/drivers/scsi/fcal.h Tue Oct 15 20:29:11 2002 @@ -23,6 +23,7 @@ int fcal_detect(Scsi_Host_Template *); int fcal_release(struct Scsi_Host *); int fcal_proc_info (char *, char **, off_t, int, int, int); +int fcal_slave_attach(Scsi_Device *); #define FCAL { \ name: "Fibre Channel Arbitrated Loop",\ @@ -30,6 +31,7 @@ release: fcal_release, \ proc_info: fcal_proc_info, \ queuecommand: fcp_scsi_queuecommand, \ + slave_attach: fcal_slave_attach, \ can_queue: FCAL_CAN_QUEUE, \ this_id: -1, \ sg_tablesize: 1, \ diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c Tue Oct 15 20:29:12 2002 +++ b/drivers/scsi/hosts.c Tue Oct 15 20:29:12 2002 @@ -229,7 +229,6 @@ if (!blk_nohighio) retval->highmem_io = tpnt->highmem_io; - retval->select_queue_depths = tpnt->select_queue_depths; retval->max_sectors = tpnt->max_sectors; retval->use_blk_tcq = tpnt->use_blk_tcq; diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h --- a/drivers/scsi/hosts.h Tue Oct 15 20:29:15 2002 +++ b/drivers/scsi/hosts.h Tue Oct 15 20:29:15 2002 @@ -266,14 +266,6 @@ */ int (* bios_param)(Disk *, struct block_device *, int []); - - /* - * Used to set the queue depth for a specific device. - * - * Once the slave_attach() function is in full use, this will go away. - */ - void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); - /* * This determines if we will use a non-interrupt driven * or an interrupt driven scheme, It is set to the maximum number @@ -384,6 +376,8 @@ */ struct Scsi_Host * next; Scsi_Device * host_queue; + struct list_head all_scsi_hosts; + struct list_head my_devices; spinlock_t default_lock; spinlock_t *host_lock; @@ -488,8 +482,6 @@ * Value host_blocked counts down from */ unsigned int max_host_blocked; - - void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *); /* * For SCSI hosts which are PCI devices, set pci_dev so that diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c --- a/drivers/scsi/ips.c Tue Oct 15 20:29:11 2002 +++ b/drivers/scsi/ips.c Tue Oct 15 20:29:11 2002 @@ -1879,10 +1879,12 @@ int min; ha = IPS_HA(SDptr->host); - min = ha->max_cmds / 4; - if (min < 8) - min = ha->max_cmds - 1; - scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min); + if (SDptr->tagged_supported) { + min = ha->max_cmds / 2; + if (min <= 16) + min = ha->max_cmds - 1; + scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min); + } return 0; } diff -Nru a/drivers/scsi/ips.h b/drivers/scsi/ips.h --- a/drivers/scsi/ips.h Tue Oct 15 20:29:14 2002 +++ b/drivers/scsi/ips.h Tue Oct 15 20:29:14 2002 @@ -429,7 +429,7 @@ can_queue : 0, \ this_id: -1, \ sg_tablesize : IPS_MAX_SG, \ - cmd_per_lun: 16, \ + cmd_per_lun: 3, \ present : 0, \ unchecked_isa_dma : 0, \ use_clustering : ENABLE_CLUSTERING, \ @@ -458,7 +458,7 @@ can_queue : 0, \ this_id: -1, \ sg_tablesize : IPS_MAX_SG, \ - cmd_per_lun: 16, \ + cmd_per_lun: 3, \ present : 0, \ unchecked_isa_dma : 0, \ use_clustering : ENABLE_CLUSTERING, \ @@ -488,7 +488,7 @@ can_queue : 0, \ this_id: -1, \ sg_tablesize : IPS_MAX_SG, \ - cmd_per_lun: 16, \ + cmd_per_lun: 3, \ present : 0, \ unchecked_isa_dma : 0, \ use_clustering : ENABLE_CLUSTERING, \ diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c --- a/drivers/scsi/ncr53c8xx.c Tue Oct 15 20:29:15 2002 +++ b/drivers/scsi/ncr53c8xx.c Tue Oct 15 20:29:15 2002 @@ -378,8 +378,6 @@ #define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f)) -static void ncr53c8xx_select_queue_depths( - struct Scsi_Host *host, struct scsi_device *devlist); static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); static void ncr53c8xx_timeout(unsigned long np); @@ -3710,7 +3708,6 @@ instance->dma_channel = 0; instance->cmd_per_lun = MAX_TAGS; instance->can_queue = (MAX_START-4); - instance->select_queue_depths = ncr53c8xx_select_queue_depths; scsi_set_pci_device(instance, device->pdev); #ifdef SCSI_NCR_INTEGRITY_CHECKING @@ -8500,56 +8497,57 @@ ** Linux select queue depths function */ -static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist) +int ncr53c8xx_slave_attach(Scsi_Device *device) { - struct scsi_device *device; + struct Scsi_Host *host = device->host; + ncb_p np; + tcb_p tp; + lcb_p lp; + int numtags, depth_to_use; - for (device = devlist; device; device = device->next) { - ncb_p np; - tcb_p tp; - lcb_p lp; - int numtags; - - if (device->host != host) - continue; - - np = ((struct host_data *) host->hostdata)->ncb; - tp = &np->target[device->id]; - lp = tp->lp[device->lun]; - - /* - ** Select queue depth from driver setup. - ** Donnot use more than configured by user. - ** Use at least 2. - ** Donnot use more than our maximum. - */ - numtags = device_queue_depth(np->unit, device->id, device->lun); - if (numtags > tp->usrtags) - numtags = tp->usrtags; - if (!device->tagged_supported) - numtags = 1; - device->queue_depth = numtags; - if (device->queue_depth < 2) - device->queue_depth = 2; - if (device->queue_depth > MAX_TAGS) - device->queue_depth = MAX_TAGS; - - /* - ** Since the queue depth is not tunable under Linux, - ** we need to know this value in order not to - ** announce stupid things to user. - */ - if (lp) { - lp->numtags = lp->maxtags = numtags; - lp->scdev_depth = device->queue_depth; - } - ncr_setup_tags (np, device->id, device->lun); + np = ((struct host_data *) host->hostdata)->ncb; + tp = &np->target[device->id]; + lp = tp->lp[device->lun]; + + /* + ** Select queue depth from driver setup. + ** Donnot use more than configured by user. + ** Use at least 2. + ** Donnot use more than our maximum. + */ + numtags = device_queue_depth(np->unit, device->id, device->lun); + if (numtags > tp->usrtags) + numtags = tp->usrtags; + if (!device->tagged_supported) + numtags = 1; + depth_to_use = numtags; + if (depth_to_use < 2) + depth_to_use = 2; + if (depth_to_use > MAX_TAGS) + depth_to_use = MAX_TAGS; + + scsi_adjust_queue_depth(device, + (device->tagged_supported ? + MSG_SIMPLE_TAG : 0), + depth_to_use); + + /* + ** Since the queue depth is not tunable under Linux, + ** we need to know this value in order not to + ** announce stupid things to user. + */ + if (lp) { + lp->numtags = lp->maxtags = numtags; + lp->scdev_depth = depth_to_use; + } + ncr_setup_tags (np, device->id, device->lun); #ifdef DEBUG_NCR53C8XX -printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", - np->unit, device->id, device->lun, device->queue_depth); + printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", + np->unit, device->id, device->lun, depth_to_use); #endif - } + + return 0; } /* diff -Nru a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h --- a/drivers/scsi/ncr53c8xx.h Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/ncr53c8xx.h Tue Oct 15 20:29:16 2002 @@ -59,6 +59,7 @@ const char *ncr53c8xx_info(struct Scsi_Host *host); int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int); +int ncr53c8xx_slave_attach(Scsi_Device *); #ifdef MODULE int ncr53c8xx_release(struct Scsi_Host *); @@ -74,6 +75,7 @@ release: ncr53c8xx_release, \ info: ncr53c8xx_info, \ queuecommand: ncr53c8xx_queue_command,\ + slave_attach: ncr53c8xx_slave_attach, \ abort: ncr53c8xx_abort, \ reset: ncr53c8xx_reset, \ bios_param: scsicam_bios_param, \ diff -Nru a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c --- a/drivers/scsi/pluto.c Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/pluto.c Tue Oct 15 20:29:16 2002 @@ -71,17 +71,21 @@ up(&fc_sem); } -static void pluto_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) +int pluto_slave_attach(Scsi_Device *device) { - Scsi_Device *device; - - for (device = devlist; device; device = device->next) { - if (device->host != host) continue; - if (device->tagged_supported) - device->queue_depth = /* 254 */ 8; - else - device->queue_depth = 2; - } + int depth_to_use; + + if (device->tagged_supported) + depth_to_use = /* 254 */ 8; + else + depth_to_use = 2; + + scsi_adjust_queue_depth(device, + (device->tagged_supported ? + MSG_SIMPLE_TAG : 0), + depth_to_use); + + return 0; } /* Detect all SSAs attached to the machine. @@ -241,7 +245,6 @@ host->unchecked_isa_dma = 1; #endif - host->select_queue_depths = pluto_select_queue_depths; fc->channels = inq->channels + 1; fc->targets = inq->targets; diff -Nru a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h --- a/drivers/scsi/pluto.h Tue Oct 15 20:29:17 2002 +++ b/drivers/scsi/pluto.h Tue Oct 15 20:29:17 2002 @@ -41,6 +41,7 @@ int pluto_detect(Scsi_Host_Template *); int pluto_release(struct Scsi_Host *); const char * pluto_info(struct Scsi_Host *); +int pluto_slave_attach(Scsi_Device *); #define PLUTO { \ name: "Sparc Storage Array 100/200", \ @@ -48,6 +49,7 @@ release: pluto_release, \ info: pluto_info, \ queuecommand: fcp_scsi_queuecommand, \ + slave_attach: pluto_slave_attach, \ can_queue: PLUTO_CAN_QUEUE, \ this_id: -1, \ sg_tablesize: 1, \ diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c --- a/drivers/scsi/qla1280.c Tue Oct 15 20:29:23 2002 +++ b/drivers/scsi/qla1280.c Tue Oct 15 20:29:23 2002 @@ -382,8 +382,7 @@ static void qla1280_next(struct scsi_qla_host *, scsi_lu_t *, int); static void qla1280_putq_t(scsi_lu_t *, srb_t *); static void qla1280_done_q_put(srb_t *, srb_t **, srb_t **); -static void qla1280_device_queue_depth(struct scsi_qla_host *, Scsi_Device *); -static void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *); +static int qla1280_slave_attach(Scsi_Device *); #if STOP_ON_ERROR static void qla1280_panic(char *, struct Scsi_Host *host); #endif @@ -840,7 +839,6 @@ host->can_queue = 0xfffff; /* unlimited */ host->cmd_per_lun = 1; - host->select_queue_depths = qla1280_select_queue_depth; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) host->base = (unsigned char *)ha->mmpbase; #else @@ -1796,7 +1794,7 @@ } /************************************************************************** - * qla1280_device_queue_depth + * qla1280_slave_attach * * Description: * Determines the queue depth for a given device. There are two ways @@ -1806,51 +1804,28 @@ * as the default queue depth. Otherwise, we use either 4 or 8 as the * default queue depth (dependent on the number of hardware SCBs). **************************************************************************/ -static void -qla1280_device_queue_depth(struct scsi_qla_host *p, Scsi_Device * device) +static int +qla1280_slave_attach(Scsi_Device * device) { - int default_depth = 3; + struct scsi_qla_host *p = (struct scsi_qla_host *)device->host->hostdata; int bus = device->channel; int target = device->id; - device->queue_depth = default_depth; - + if (qla1280_check_for_dead_scsi_bus(p, bus)) + return 1; if (device->tagged_supported && (p->bus_settings[bus].qtag_enables & (BIT_0 << target))) { - device->tagged_queue = 1; - device->current_tag = 0; - device->queue_depth = p->bus_settings[bus].hiwat; + scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, + p->bus_settings[bus].hiwat); /* device->queue_depth = 20; */ printk(KERN_INFO "scsi(%li:%d:%d:%d): Enabled tagged queuing, " "queue depth %d.\n", p->host_no, device->channel, - device->id, device->lun, device->queue_depth); + device->id, device->lun, device->new_queue_depth); + } else { + scsi_adjust_queue_depth(device, 0 /* TCQ off */, 3); } qla12160_get_target_parameters(p, bus, target, device->lun); -} - -/************************************************************************** - * qla1280_select_queue_depth - * - * Sets the queue depth for each SCSI device hanging off the input - * host adapter. We use a queue depth of 2 for devices that do not - * support tagged queueing. - **************************************************************************/ -static void -qla1280_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs) -{ - Scsi_Device *device; - struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; - - ENTER("qla1280_select_queue_depth"); - for (device = scsi_devs; device != NULL; device = device->next) { - if (device->host == host) - qla1280_device_queue_depth (ha, device); - } - - if (scsi_devs) - qla1280_check_for_dead_scsi_bus(ha, scsi_devs->channel); - - LEAVE("qla1280_select_queue_depth"); + return 0; } /* diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h --- a/drivers/scsi/qla1280.h Tue Oct 15 20:29:23 2002 +++ b/drivers/scsi/qla1280.h Tue Oct 15 20:29:23 2002 @@ -1314,6 +1314,7 @@ int qla1280_abort(Scsi_Cmnd *); int qla1280_reset(Scsi_Cmnd *, unsigned int); int qla1280_biosparam(Disk *, struct block_device *, int[]); +static int qla1280_slave_attach(Scsi_Device *); void qla1280_intr_handler(int, void *, struct pt_regs *); void qla1280_setup(char *s, int *dummy); @@ -1342,7 +1343,7 @@ /* use_new_eh_code: 0, */ \ abort: qla1280_abort, \ reset: qla1280_reset, \ - slave_attach: NULL, \ + slave_attach: qla1280_slave_attach, \ bios_param: qla1280_biosparam, \ can_queue: 255, /* max simultaneous cmds */\ this_id: -1, /* scsi id of host adapter */\ diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Tue Oct 15 20:29:17 2002 +++ b/drivers/scsi/scsi.c Tue Oct 15 20:29:17 2002 @@ -568,7 +568,7 @@ atomic_read(&SCpnt->host->host_active), SCpnt->host->host_failed)); - if(SDpnt->queue_depth > SDpnt->new_queue_depth) { + if(SDpnt->current_queue_depth > SDpnt->new_queue_depth) { Scsi_Cmnd *prev, *next; /* * Release the command block and decrement the queue @@ -582,10 +582,10 @@ else prev->next = next->next; kfree((char *)SCpnt); - SDpnt->queue_depth--; - } else if(SDpnt->queue_depth < SDpnt->new_queue_depth) { + SDpnt->current_queue_depth--; + } else if(SDpnt->current_queue_depth < SDpnt->new_queue_depth) { alloc_cmd = 1; - SDpnt->queue_depth++; + SDpnt->current_queue_depth++; } spin_unlock_irqrestore(&device_request_lock, flags); @@ -633,7 +633,7 @@ spin_unlock_irqrestore(&device_request_lock, flags); } else { spin_lock_irqsave(&device_request_lock, flags); - SDpnt->queue_depth--; + SDpnt->current_queue_depth--; spin_unlock_irqrestore(&device_request_lock, flags); } } @@ -1399,14 +1399,10 @@ */ int scsi_retry_command(Scsi_Cmnd * SCpnt) { - memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, - sizeof(SCpnt->data_cmnd)); - SCpnt->request_buffer = SCpnt->buffer; - SCpnt->request_bufflen = SCpnt->bufflen; - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->cmd_len = SCpnt->old_cmd_len; - SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; - SCpnt->underflow = SCpnt->old_underflow; + /* + * Restore the SCSI command state. + */ + scsi_setup_cmd_retry(SCpnt); /* * Zero the sense information from the last time we tried @@ -1509,7 +1505,7 @@ SDpnt->device_queue = SCnext = SCpnt->next; kfree((char *) SCpnt); } - SDpnt->queue_depth = 0; + SDpnt->current_queue_depth = 0; SDpnt->new_queue_depth = 0; spin_unlock_irqrestore(&device_request_lock, flags); } @@ -1533,7 +1529,7 @@ unsigned long flags; Scsi_Cmnd *SCpnt; - if (SDpnt->queue_depth != 0) + if (SDpnt->current_queue_depth != 0) return; SCpnt = (Scsi_Cmnd *) kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC | @@ -1571,7 +1567,7 @@ spin_lock_irqsave(&device_request_lock, flags); if(SDpnt->new_queue_depth == 0) SDpnt->new_queue_depth = 1; - SDpnt->queue_depth++; + SDpnt->current_queue_depth++; SCpnt->next = SDpnt->device_queue; SDpnt->device_queue = SCpnt; spin_unlock_irqrestore(&device_request_lock, flags); @@ -1601,12 +1597,13 @@ * * If cmdblocks != 0 then we are a live device. We just set the * new_queue_depth variable and when the scsi completion handler - * notices that queue_depth != new_queue_depth it will work to - * rectify the situation. If new_queue_depth is less than current - * queue_depth, then it will free the completed command instead of - * putting it back on the free list and dec queue_depth. Otherwise - * it will try to allocate a new command block for the device and - * put it on the free list along with the command that is being + * notices that current_queue_depth != new_queue_depth it will + * work to rectify the situation. If new_queue_depth is less than + * current_queue_depth, then it will free the completed command + * instead of putting it back on the free list and dec + * current_queue_depth. Otherwise it will try to allocate a new + * command block for the device and put it on the free list along + * with the command that is being * completed. Obviously, if the device isn't doing anything then * neither is this code, so it will bring the devices queue depth * back into line when the device is actually being used. This @@ -1652,14 +1649,11 @@ SDpnt->channel, SDpnt->id, SDpnt->lun); case 0: SDpnt->ordered_tags = SDpnt->simple_tags = 0; - if(SDpnt->host->cmd_per_lun) - SDpnt->new_queue_depth = SDpnt->host->cmd_per_lun; - else - SDpnt->new_queue_depth = 1; + SDpnt->new_queue_depth = tags; break; } spin_unlock_irqrestore(&device_request_lock, flags); - if(SDpnt->queue_depth == 0) + if(SDpnt->current_queue_depth == 0) { scsi_build_commandblocks(SDpnt); } @@ -2120,7 +2114,7 @@ (*sdtpnt->attach) (SDpnt); if (SDpnt->attached) { scsi_build_commandblocks(SDpnt); - if (SDpnt->queue_depth == 0) + if (SDpnt->current_queue_depth == 0) out_of_space = 1; } } @@ -2409,10 +2403,10 @@ * If this driver attached to the device, and don't have any * command blocks for this device, allocate some. */ - if (SDpnt->attached && SDpnt->queue_depth == 0) { + if (SDpnt->attached && SDpnt->current_queue_depth == 0) { SDpnt->online = TRUE; scsi_build_commandblocks(SDpnt); - if (SDpnt->queue_depth == 0) + if (SDpnt->current_queue_depth == 0) out_of_space = 1; } } @@ -2820,7 +2814,7 @@ SDpnt->new_queue_depth = 1; scsi_build_commandblocks(SDpnt); - if(SDpnt->queue_depth == 0) { + if(SDpnt->current_queue_depth == 0) { kfree(SDpnt); return NULL; } diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Tue Oct 15 20:29:14 2002 +++ b/drivers/scsi/scsi.h Tue Oct 15 20:29:14 2002 @@ -467,6 +467,7 @@ int sectors); extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *); extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt); +extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt); extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int); extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors, int block_sectors); @@ -556,15 +557,19 @@ */ struct scsi_device *next; /* Used for linked list */ struct scsi_device *prev; /* Used for linked list */ + struct list_head siblings; /* list of all devices on this host */ + struct list_head same_target_siblings; /* just the devices sharing same target id */ wait_queue_head_t scpnt_wait; /* Used to wait if device is busy */ struct Scsi_Host *host; request_queue_t request_queue; atomic_t device_active; /* commands checked out for device */ volatile unsigned short device_busy; /* commands actually active on low-level */ + struct list_head free_cmnds; /* list of available Scsi_Cmnd structs */ + struct list_head busy_cmnds; /* list of Scsi_Cmnd structs in use */ Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */ Scsi_Cmnd *current_cmnd; /* currently active command */ - unsigned short queue_depth; /* How deep of a queue we have */ + unsigned short current_queue_depth;/* How deep of a queue we have */ unsigned short new_queue_depth; /* How deep of a queue we want */ unsigned int id, lun, channel; @@ -597,9 +602,10 @@ unsigned changed:1; /* Data invalid due to media change */ unsigned busy:1; /* Used to prevent races */ unsigned lockable:1; /* Able to prevent media removal */ + unsigned locked:1; /* Media removal disabled */ unsigned borken:1; /* Tell the Seagate driver to be * painfully slow on this device */ -// unsigned disconnect:1; /* can disconnect */ + unsigned disconnect:1; /* can disconnect */ unsigned soft_reset:1; /* Uses soft reset option */ unsigned sdtr:1; /* Device supports SDTR messages */ unsigned wdtr:1; /* Device supports WDTR messages */ @@ -711,6 +717,7 @@ Scsi_Request *sc_request; struct scsi_cmnd *next; struct scsi_cmnd *reset_chain; + struct list_head list_entry; /* Used to place us on the cmd lists */ int eh_state; /* Used for state tracking in error handlr */ int eh_eflags; /* Used by error handlr */ @@ -974,5 +981,7 @@ #define SCSI_EH_REC_TIMEOUT 0x0008 /* Recovery cmd timeout */ #define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70) + +int scsi_set_medium_removal(Scsi_Device *dev, char state); #endif diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c Tue Oct 15 20:29:11 2002 +++ b/drivers/scsi/scsi_error.c Tue Oct 15 20:29:11 2002 @@ -8,6 +8,10 @@ * * Restructured scsi_unjam_host and associated functions. * September 04, 2002 Mike Anderson (andmike@us.ibm.com) + * + * Forward port of Russell King's (rmk@arm.linux.org.uk) changes and + * minor cleanups. + * September 30, 2002 Mike Anderson (andmike@us.ibm.com) */ #include @@ -35,6 +39,8 @@ #include "scsi.h" #include "hosts.h" +#include /* grr */ + /* * We must always allow SHUTDOWN_SIGS. Even if we are not a module, * the host drivers that we are using may be loaded as modules, and @@ -59,7 +65,7 @@ * These should *probably* be handled by the host itself. * Since it is allowed to sleep, it probably should. */ -#define BUS_RESET_SETTLE_TIME 5*HZ +#define BUS_RESET_SETTLE_TIME 10*HZ #define HOST_RESET_SETTLE_TIME 10*HZ /** @@ -91,9 +97,9 @@ scmd->eh_timeout.expires = jiffies + timeout; scmd->eh_timeout.function = (void (*)(unsigned long)) complete; - SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at" - "%d (%p)\n", scmd, timeout, - complete)); + SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:" + " %d, (%p)\n", __FUNCTION__, + scmd, timeout, complete)); add_timer(&scmd->eh_timeout); @@ -116,8 +122,9 @@ rtn = del_timer(&scmd->eh_timeout); - SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p" - " %d\n", scmd, rtn)); + SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p," + " rtn: %d\n", __FUNCTION__, + scmd, rtn)); scmd->eh_timeout.data = (unsigned long) NULL; scmd->eh_timeout.function = NULL; @@ -150,7 +157,7 @@ scsi_host_failed_inc_and_test(scmd->host); SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d " - "failed=%d\n", + " failed=%d\n", atomic_read(&scmd->host->host_active), scmd->host->host_busy, scmd->host->host_failed)); @@ -173,7 +180,7 @@ SCSI_SLEEP(&sdev->host->host_wait, sdev->host->in_recovery); - SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n", + SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__, sdev->online)); return sdev->online; @@ -209,10 +216,10 @@ if (cmd_timed_out || cmd_failed) { SCSI_LOG_ERROR_RECOVERY(3, - printk("scsi_eh: %d:%d:%d:%d cmds failed: %d," - "timedout: %d\n", - shost->host_no, sdev->channel, - sdev->id, sdev->lun, + printk("%s: %d:%d:%d:%d cmds failed: %d," + " timedout: %d\n", + __FUNCTION__, shost->host_no, + sdev->channel, sdev->id, sdev->lun, cmd_failed, cmd_timed_out)); cmd_timed_out = 0; cmd_failed = 0; @@ -220,8 +227,8 @@ } } - SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d " - "devices require eh work\n", + SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d" + " devices require eh work\n", total_failures, devices_failed)); } #endif @@ -265,10 +272,10 @@ * queued and will be finished along the * way. */ - SCSI_LOG_ERROR_RECOVERY(1, printk("Error hdlr " - "prematurely woken " - "cmds still active " - "(%p %x %d)\n", + SCSI_LOG_ERROR_RECOVERY(1, printk("Error hdlr" + " prematurely woken" + " cmds still active" + " (%p %x %d)\n", scmd, scmd->state, scmd->target)); } @@ -278,12 +285,17 @@ SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(*sc_list, shost)); - BUG_ON(shost->host_failed != found); + if (shost->host_failed != found) + printk(KERN_ERR "%s: host_failed: %d != found: %d\n", + __FUNCTION__, shost->host_failed, found); } /** * scsi_check_sense - Examine scsi cmd sense * @scmd: Cmd to have sense checked. + * + * Return value: + * SUCCESS or FAILED or NEEDS_RETRY **/ static int scsi_check_sense(Scsi_Cmnd *scmd) { @@ -353,7 +365,6 @@ **/ static int scsi_eh_completed_normally(Scsi_Cmnd *scmd) { - int rtn; /* * first check the host byte, to see if there is anything in there @@ -369,7 +380,7 @@ * SUCCESS. */ scmd->flags &= ~IS_RESETTING; - goto maybe_retry; + return NEEDS_RETRY; } /* * rats. we are already in the error handler, so we now @@ -377,10 +388,7 @@ * is valid, we have a pretty good idea of what to do. * if not, we mark it as FAILED. */ - rtn = scsi_check_sense(scmd); - if (rtn == NEEDS_RETRY) - goto maybe_retry; - return rtn; + return scsi_check_sense(scmd); } if (host_byte(scmd->result) != DID_OK) { return FAILED; @@ -400,10 +408,7 @@ case COMMAND_TERMINATED: return SUCCESS; case CHECK_CONDITION: - rtn = scsi_check_sense(scmd); - if (rtn == NEEDS_RETRY) - goto maybe_retry; - return rtn; + return scsi_check_sense(scmd); case CONDITION_GOOD: case INTERMEDIATE_GOOD: case INTERMEDIATE_C_GOOD: @@ -418,14 +423,6 @@ return FAILED; } return FAILED; - - maybe_retry: - if ((++scmd->retries) < scmd->allowed) { - return NEEDS_RETRY; - } else { - /* no more retries - report this one back to upper level */ - return SUCCESS; - } } /** @@ -440,12 +437,13 @@ static void scsi_eh_times_out(Scsi_Cmnd *scmd) { scsi_eh_eflags_set(scmd, SCSI_EH_REC_TIMEOUT); - SCSI_LOG_ERROR_RECOVERY(3, printk("in scsi_eh_times_out %p\n", scmd)); + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd:%p\n", __FUNCTION__, + scmd)); if (scmd->host->eh_action != NULL) up(scmd->host->eh_action); else - printk("missing scsi error handler thread\n"); + printk("%s: eh_action NULL\n", __FUNCTION__); } /** @@ -471,8 +469,8 @@ scmd->owner = SCSI_OWNER_ERROR_HANDLER; - SCSI_LOG_ERROR_RECOVERY(3, printk("in eh_done %p result:%x\n", scmd, - scmd->result)); + SCSI_LOG_ERROR_RECOVERY(3, printk("%s scmd: %p result: %x\n", + __FUNCTION__, scmd, scmd->result)); if (scmd->host->eh_action != NULL) up(scmd->host->eh_action); @@ -488,7 +486,7 @@ * this case, and furthermore, there is a different completion handler * vs scsi_dispatch_cmd. * Return value: - * SUCCESS/FAILED + * SUCCESS or FAILED or NEEDS_RETRY **/ static int scsi_send_eh_cmnd(Scsi_Cmnd *scmd, int timeout) { @@ -498,7 +496,6 @@ ASSERT_LOCK(host->host_lock, 0); -retry: /* * we will use a queued command if possible, otherwise we will * emulate the queuing and calling of completion function ourselves. @@ -552,9 +549,8 @@ rtn = FAILED; } - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: %p rtn:%x\n", - __FUNCTION__, scmd, - rtn)); + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n", + __FUNCTION__, scmd, rtn)); } else { int temp; @@ -576,16 +572,15 @@ * actually did complete normally. */ if (rtn == SUCCESS) { - int ret = scsi_eh_completed_normally(scmd); + int rtn = scsi_eh_completed_normally(scmd); SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scsi_eh_completed_normally %x\n", - __FUNCTION__, ret)); - switch (ret) { + __FUNCTION__, rtn)); + switch (rtn) { case SUCCESS: - break; case NEEDS_RETRY: - goto retry; case FAILED: + break; default: rtn = FAILED; break; @@ -622,7 +617,7 @@ ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA); if (scsi_result == NULL) { - printk("cannot allocate scsi_result in scsi_request_sense.\n"); + printk("%s: cannot allocate scsi_result.\n", __FUNCTION__); return FAILED; } /* @@ -657,15 +652,8 @@ * when we eventually call scsi_finish, we really wish to complete * the original request, so let's restore the original data. (db) */ - memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd, - sizeof(scmd->data_cmnd)); + scsi_setup_cmd_retry(scmd); scmd->result = saved_result; - scmd->request_buffer = scmd->buffer; - scmd->request_bufflen = scmd->bufflen; - scmd->use_sg = scmd->old_use_sg; - scmd->cmd_len = scmd->old_cmd_len; - scmd->sc_data_direction = scmd->sc_old_data_direction; - scmd->underflow = scmd->old_underflow; /* * hey, we are done. let's look to see what happened. @@ -683,16 +671,16 @@ **/ static int scsi_eh_retry_cmd(Scsi_Cmnd *scmd) { - memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd, - sizeof(scmd->data_cmnd)); - scmd->request_buffer = scmd->buffer; - scmd->request_bufflen = scmd->bufflen; - scmd->use_sg = scmd->old_use_sg; - scmd->cmd_len = scmd->old_cmd_len; - scmd->sc_data_direction = scmd->sc_old_data_direction; - scmd->underflow = scmd->old_underflow; + int rtn = SUCCESS; - return scsi_send_eh_cmnd(scmd, scmd->timeout_per_command); + for (; scmd->retries < scmd->allowed; scmd->retries++) { + scsi_setup_cmd_retry(scmd); + rtn = scsi_send_eh_cmnd(scmd, scmd->timeout_per_command); + if (rtn != NEEDS_RETRY) + break; + } + + return rtn; } /** @@ -717,9 +705,7 @@ * set this back so that the upper level can correctly free up * things. */ - scmd->use_sg = scmd->old_use_sg; - scmd->sc_data_direction = scmd->sc_old_data_direction; - scmd->underflow = scmd->old_underflow; + scsi_setup_cmd_retry(scmd); } /** @@ -758,14 +744,14 @@ continue; SCSI_LOG_ERROR_RECOVERY(2, printk("%s: requesting sense" - "for %d\n", __FUNCTION__, - scmd->target)); + " for tgt: %d\n", + __FUNCTION__, scmd->target)); rtn = scsi_request_sense(scmd); if (rtn != SUCCESS) continue; SCSI_LOG_ERROR_RECOVERY(3, printk("sense requested for %p" - "- result %x\n", scmd, + " result %x\n", scmd, scmd->result)); SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", scmd)); @@ -847,7 +833,9 @@ static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; int rtn; + int retry_cnt = 1; +retry_tur: memcpy((void *) scmd->cmnd, (void *) tur_command, sizeof(tur_command)); @@ -873,32 +861,18 @@ * when we eventually call scsi_finish, we really wish to complete * the original request, so let's restore the original data. (db) */ - memcpy((void *) scmd->cmnd, (void *) scmd->data_cmnd, - sizeof(scmd->data_cmnd)); - scmd->request_buffer = scmd->buffer; - scmd->request_bufflen = scmd->bufflen; - scmd->use_sg = scmd->old_use_sg; - scmd->cmd_len = scmd->old_cmd_len; - scmd->sc_data_direction = scmd->sc_old_data_direction; - scmd->underflow = scmd->old_underflow; + scsi_setup_cmd_retry(scmd); /* * hey, we are done. let's look to see what happened. */ - SCSI_LOG_ERROR_RECOVERY(3, - printk("%s: scmd %p rtn %x\n", + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", __FUNCTION__, scmd, rtn)); - if ((rtn == SUCCESS) && scmd->result) { - if (((driver_byte(scmd->result) & DRIVER_SENSE) || - (status_byte(scmd->result) & CHECK_CONDITION)) && - (SCSI_SENSE_VALID(scmd))) { - if (((scmd->sense_buffer[2] & 0xf) != NOT_READY) && - ((scmd->sense_buffer[2] & 0xf) != UNIT_ATTENTION) && - ((scmd->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) { - return 0; - } - } - } + if (rtn == SUCCESS) + return 0; + else if (rtn == NEEDS_RETRY) + if (retry_cnt--) + goto retry_tur; return 1; } @@ -929,7 +903,7 @@ rtn = scsi_try_to_abort_cmd(scmd); if (rtn == SUCCESS) { - if (scsi_eh_tur(scmd)) { + if (!scsi_eh_tur(scmd)) { rtn = scsi_eh_retry_cmd(scmd); if (rtn == SUCCESS) scsi_eh_finish_cmd(scmd, shost); @@ -963,6 +937,11 @@ rtn = scmd->host->hostt->eh_device_reset_handler(scmd); spin_unlock_irqrestore(scmd->host->host_lock, flags); + if (rtn == SUCCESS) { + scmd->device->was_reset = 1; + scmd->device->expecting_cc_ua = 1; + } + return rtn; } @@ -999,7 +978,7 @@ * a bus device reset to it. */ rtn = scsi_try_bus_device_reset(scmd); - if ((rtn == SUCCESS) && (scsi_eh_tur(scmd))) + if ((rtn == SUCCESS) && (!scsi_eh_tur(scmd))) for (scmd = sc_todo; scmd; scmd = scmd->bh_next) if ((scmd->device == sdev) && scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) { @@ -1141,7 +1120,7 @@ if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR) || channel != scmd->channel) continue; - if (scsi_eh_tur(scmd)) { + if (!scsi_eh_tur(scmd)) { rtn = scsi_eh_retry_cmd(scmd); if (rtn == SUCCESS) @@ -1168,10 +1147,10 @@ if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CMD_ERR)) continue; - printk(KERN_INFO "%s: Device set offline - not" - "ready or command retry failed" - "after error recovery: host" - "%d channel %d id %d lun %d\n", + printk(KERN_INFO "%s: Device offlined - not" + " ready or command retry failed" + " after error recovery: host" + " %d channel %d id %d lun %d\n", __FUNCTION__, shost->host_no, scmd->device->channel, scmd->device->id, @@ -1243,7 +1222,7 @@ */ if (scmd->device->online == FALSE) { SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report" - "as SUCCESS\n", + " as SUCCESS\n", __FUNCTION__)); return SUCCESS; } @@ -1367,7 +1346,7 @@ return SUCCESS; case RESERVATION_CONFLICT: - printk("scsi%d (%d,%d,%d) : reservation conflict\n", + printk("scsi%d (%d,%d,%d) : reservation conflict\n", scmd->host->host_no, scmd->channel, scmd->device->id, scmd->device->lun); return SUCCESS; /* causes immediate i/o error */ @@ -1389,6 +1368,75 @@ } /** + * scsi_eh_lock_done - done function for eh door lock request + * @scmd: SCSI command block for the door lock request + * + * Notes: + * We completed the asynchronous door lock request, and it has either + * locked the door or failed. We must free the command structures + * associated with this request. + **/ +static void scsi_eh_lock_done(struct scsi_cmnd *scmd) +{ + struct scsi_request *sreq = scmd->sc_request; + + scmd->sc_request = NULL; + sreq->sr_command = NULL; + + scsi_release_command(scmd); + scsi_release_request(sreq); +} + + +/** + * scsi_eh_lock_door - Prevent medium removal for the specified device + * @sdev: SCSI device to prevent medium removal + * + * Locking: + * We must be called from process context; scsi_allocate_request() + * may sleep. + * + * Notes: + * We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the + * head of the devices request queue, and continue. + * + * Bugs: + * scsi_allocate_request() may sleep waiting for existing requests to + * be processed. However, since we haven't kicked off any request + * processing for this host, this may deadlock. + * + * If scsi_allocate_request() fails for what ever reason, we + * completely forget to lock the door. + **/ +static void scsi_eh_lock_door(struct scsi_device *sdev) +{ + struct scsi_request *sreq = scsi_allocate_request(sdev); + + if (sreq == NULL) { + printk(KERN_ERR "%s: request allocate failed," + "prevent media removal cmd not sent", __FUNCTION__); + return; + } + + sreq->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL; + sreq->sr_cmnd[1] = (sdev->scsi_level <= SCSI_2) ? (sdev->lun << 5) : 0; + sreq->sr_cmnd[2] = 0; + sreq->sr_cmnd[3] = 0; + sreq->sr_cmnd[4] = SCSI_REMOVAL_PREVENT; + sreq->sr_cmnd[5] = 0; + sreq->sr_data_direction = SCSI_DATA_NONE; + sreq->sr_bufflen = 0; + sreq->sr_buffer = NULL; + sreq->sr_allowed = 5; + sreq->sr_done = scsi_eh_lock_done; + sreq->sr_timeout_per_command = 10 * HZ; + sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]); + + scsi_insert_special_req(sreq, 1); +} + + +/** * scsi_restart_operations - restart io operations to the specified host. * @shost: Host we are restarting. * @@ -1404,6 +1452,15 @@ ASSERT_LOCK(shost->host_lock, 0); /* + * If the door was locked, we need to insert a door lock request + * onto the head of the SCSI request queue for the device. There + * is no point trying to lock the door of an off-line device. + */ + for (sdev = shost->host_queue; sdev; sdev = sdev->next) + if (sdev->online && sdev->locked) + scsi_eh_lock_door(sdev); + + /* * next free up anything directly waiting upon the host. this * will be requests for character device operations, and also for * ioctls to queued block devices. @@ -1426,8 +1483,7 @@ if ((shost->can_queue > 0 && (shost->host_busy >= shost->can_queue)) || (shost->host_blocked) - || (shost->host_self_blocked) - || (sdev->device_blocked)) { + || (shost->host_self_blocked)) { break; } @@ -1475,7 +1531,7 @@ if (scsi_eh_get_sense(sc_todo, shost)) if (scsi_eh_abort_cmd(sc_todo, shost)) if (scsi_eh_bus_device_reset(sc_todo, shost)) - if(scsi_eh_bus_host_reset(sc_todo, shost)) + if (scsi_eh_bus_host_reset(sc_todo, shost)) scsi_eh_offline_sdevs(sc_todo, shost); BUG_ON(shost->host_failed); @@ -1563,8 +1619,7 @@ /* * Wake up the thread that created us. */ - SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", - shost->eh_notify->count.counter)); + SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent \n")); up(shost->eh_notify); diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c --- a/drivers/scsi/scsi_ioctl.c Tue Oct 15 20:29:22 2002 +++ b/drivers/scsi/scsi_ioctl.c Tue Oct 15 20:29:22 2002 @@ -151,6 +151,29 @@ return result; } +int scsi_set_medium_removal(Scsi_Device *dev, char state) +{ + char scsi_cmd[MAX_COMMAND_SIZE]; + int ret; + + if (!dev->removable || !dev->lockable) + return 0; + + scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; + scsi_cmd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0; + scsi_cmd[2] = 0; + scsi_cmd[3] = 0; + scsi_cmd[4] = state; + scsi_cmd[5] = 0; + + ret = ioctl_internal_command(dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); + + if (ret == 0) + dev->locked = state == SCSI_REMOVAL_PREVENT; + + return ret; +} + /* * This interface is deprecated - users should use the scsi generic (sg) * interface instead, as this is a more flexible approach to performing @@ -456,24 +479,9 @@ return scsi_ioctl_send_command((Scsi_Device *) dev, (Scsi_Ioctl_Command *) arg); case SCSI_IOCTL_DOORLOCK: - if (!dev->removable || !dev->lockable) - return 0; - scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = cmd_byte1; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = SCSI_REMOVAL_PREVENT; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, - IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); - break; + return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT); case SCSI_IOCTL_DOORUNLOCK: - if (!dev->removable || !dev->lockable) - return 0; - scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = cmd_byte1; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = SCSI_REMOVAL_ALLOW; - return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd, - IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); + return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW); case SCSI_IOCTL_TEST_UNIT_READY: scsi_cmd[0] = TEST_UNIT_READY; scsi_cmd[1] = cmd_byte1; diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Tue Oct 15 20:29:17 2002 +++ b/drivers/scsi/scsi_lib.c Tue Oct 15 20:29:17 2002 @@ -160,6 +160,30 @@ } /* + * Function: scsi_setup_cmd_retry() + * + * Purpose: Restore the command state for a retry + * + * Arguments: SCpnt - command to be restored + * + * Returns: Nothing + * + * Notes: Immediately prior to retrying a command, we need + * to restore certain fields that we saved above. + */ +void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt) +{ + memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd, + sizeof(SCpnt->data_cmnd)); + SCpnt->request_buffer = SCpnt->buffer; + SCpnt->request_bufflen = SCpnt->bufflen; + SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; + SCpnt->underflow = SCpnt->old_underflow; +} + +/* * Function: scsi_queue_next_request() * * Purpose: Handle post-processing of completed commands. @@ -614,7 +638,7 @@ printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ", SCpnt->host->host_no, (int) SCpnt->channel, (int) SCpnt->target, (int) SCpnt->lun); - print_command(SCpnt->cmnd); + print_command(SCpnt->data_cmnd); print_sense("sd", SCpnt); SCpnt = scsi_end_request(SCpnt, 0, block_sectors); return; @@ -796,33 +820,6 @@ break; } else { SDpnt->starved = 0; - } - - /* - * FIXME(eric) - * I am not sure where the best place to do this is. We need - * to hook in a place where we are likely to come if in user - * space. Technically the error handling thread should be - * doing this crap, but the error handler isn't used by - * most hosts. - */ - if (SDpnt->was_reset) { - /* - * We need to relock the door, but we might - * be in an interrupt handler. Only do this - * from user space, since we do not want to - * sleep from an interrupt. - * - * FIXME(eric) - have the error handler thread do - * this work. - */ - SDpnt->was_reset = 0; - if (SDpnt->removable && !in_interrupt()) { - spin_unlock_irq(q->queue_lock); - scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0); - spin_lock_irq(q->queue_lock); - continue; - } } /* diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Tue Oct 15 20:29:20 2002 +++ b/drivers/scsi/scsi_scan.c Tue Oct 15 20:29:20 2002 @@ -1532,7 +1532,7 @@ */ sdevscan->new_queue_depth = 1; scsi_build_commandblocks(sdevscan); - if (sdevscan->queue_depth == 0) + if (sdevscan->current_queue_depth == 0) goto alloc_failed; sreq = scsi_allocate_request(sdevscan); @@ -1606,7 +1606,7 @@ kfree(scsi_result); if (sreq != NULL) scsi_release_request(sreq); - if (sdevscan->queue_depth != 0) + if (sdevscan->current_queue_depth != 0) scsi_release_commandblocks(sdevscan); return SCSI_SCAN_NO_RESPONSE; } @@ -1762,7 +1762,7 @@ sdevscan->new_queue_depth = 1; scsi_build_commandblocks(sdevscan); - if (sdevscan->queue_depth == 0) { + if (sdevscan->current_queue_depth == 0) { printk(ALLOC_FAILURE_MSG, __FUNCTION__); /* * We are out of memory, don't try scanning any further. @@ -2030,7 +2030,7 @@ (*sdt->attach) (sdev); if (sdev->attached) { scsi_build_commandblocks(sdev); - if (sdev->queue_depth == 0) + if (sdev->current_queue_depth == 0) printk(ALLOC_FAILURE_MSG, __FUNCTION__); } diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c --- a/drivers/scsi/scsi_syms.c Tue Oct 15 20:29:17 2002 +++ b/drivers/scsi/scsi_syms.c Tue Oct 15 20:29:17 2002 @@ -54,6 +54,7 @@ EXPORT_SYMBOL(print_Scsi_Cmnd); EXPORT_SYMBOL(scsi_block_when_processing_errors); EXPORT_SYMBOL(scsi_ioctl_send_command); +EXPORT_SYMBOL(scsi_set_medium_removal); #if defined(CONFIG_SCSI_LOGGING) /* { */ EXPORT_SYMBOL(scsi_logging_level); #endif diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Tue Oct 15 20:29:19 2002 +++ b/drivers/scsi/sd.c Tue Oct 15 20:29:19 2002 @@ -529,7 +529,7 @@ if (sdp->removable) if (sdp->access_count==1) if (scsi_block_when_processing_errors(sdp)) - scsi_ioctl(sdp, SCSI_IOCTL_DOORLOCK, NULL); + scsi_set_medium_removal(sdp, SCSI_REMOVAL_PREVENT); return 0; @@ -573,7 +573,7 @@ if (sdp->removable) { if (!sdp->access_count) if (scsi_block_when_processing_errors(sdp)) - scsi_ioctl(sdp, SCSI_IOCTL_DOORUNLOCK, NULL); + scsi_set_medium_removal(sdp, SCSI_REMOVAL_ALLOW); } if (sdp->host->hostt->module) __MOD_DEC_USE_COUNT(sdp->host->hostt->module); @@ -916,7 +916,7 @@ SRpnt->sr_data_direction = SCSI_DATA_READ; scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - 24, SD_TIMEOUT, MAX_RETRIES); + 128, SD_TIMEOUT, MAX_RETRIES); the_result = SRpnt->sr_result; retries--; @@ -1386,7 +1386,7 @@ ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD))) return 0; - gd = alloc_disk(); + gd = alloc_disk(16); if (!gd) return 1; @@ -1423,7 +1423,6 @@ gd->de = sdp->de; gd->major = SD_MAJOR(dsk_nr>>4); gd->first_minor = (dsk_nr & 15)<<4; - gd->minor_shift = 4; gd->fops = &sd_fops; if (dsk_nr > 26) sprintf(gd->disk_name, "sd%c%c",'a'+dsk_nr/26-1,'a'+dsk_nr%26); @@ -1623,7 +1622,6 @@ } the_result = SRpnt->sr_result; - scsi_release_request(SRpnt); if(verbose) { if(the_result != 0) { printk("FAILED\n status = %x, message = %02x, host = %d, driver = %02x\n ", @@ -1636,6 +1634,7 @@ } } + scsi_release_request(SRpnt); return (the_result == 0); } diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/sg.c Tue Oct 15 20:29:16 2002 @@ -852,7 +852,7 @@ __put_user((int) sdp->device->type, &sg_idp->scsi_type); __put_user((short) sdp->device->host->cmd_per_lun, &sg_idp->h_cmd_per_lun); - __put_user((short) sdp->device->queue_depth, + __put_user((short) sdp->device->new_queue_depth, &sg_idp->d_queue_depth); __put_user(0, &sg_idp->unused[0]); __put_user(0, &sg_idp->unused[1]); @@ -3039,7 +3039,7 @@ scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, (int) scsidp->type, (int) scsidp->access_count, - (int) scsidp->queue_depth, + (int) scsidp->new_queue_depth, (int) scsidp->device_busy, (int) scsidp->online); else diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Tue Oct 15 20:29:14 2002 +++ b/drivers/scsi/sr.c Tue Oct 15 20:29:14 2002 @@ -575,7 +575,7 @@ void get_capabilities(Scsi_CD *cd) { - unsigned char cmd[6]; + struct cdrom_generic_command cgc; unsigned char *buffer; int rc, n; @@ -597,13 +597,18 @@ printk(KERN_ERR "sr: out of memory.\n"); return; } - cmd[0] = MODE_SENSE; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun << 5) & 0xe0) : 0; - cmd[2] = 0x2a; - cmd[4] = 128; - cmd[3] = cmd[5] = 0; - rc = sr_do_ioctl(cd, cmd, buffer, 128, 1, SCSI_DATA_READ, NULL); + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = MODE_SENSE; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + ((cd->device->lun << 5) & 0xe0) : 0; + cgc.cmd[2] = 0x2a; + cgc.cmd[4] = 128; + cgc.buffer = buffer; + cgc.buflen = 128; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = SR_TIMEOUT; + rc = sr_do_ioctl(cd, &cgc); if (rc) { /* failed, drive doesn't have capabilities mode page */ @@ -680,7 +685,10 @@ if (device->scsi_level <= SCSI_2) cgc->cmd[1] |= device->lun << 5; - cgc->stat = sr_do_ioctl(cdi->handle, cgc->cmd, cgc->buffer, cgc->buflen, cgc->quiet, cgc->data_direction, cgc->sense); + if (cgc->timeout <= 0) + cgc->timeout = IOCTL_TIMEOUT; + + sr_do_ioctl(cdi->handle, cgc); return cgc->stat; } @@ -718,24 +726,6 @@ return 1; } -/* Driverfs file support */ -static ssize_t sr_device_kdev_read(struct device *driverfs_dev, - char *page, size_t count, loff_t off) -{ - kdev_t kdev; - kdev.value=(int)(long)driverfs_dev->driver_data; - return off ? 0 : sprintf(page, "%x\n",kdev.value); -} -static DEVICE_ATTR(kdev,S_IRUGO,sr_device_kdev_read,NULL); - -static ssize_t sr_device_type_read(struct device *driverfs_dev, - char *page, size_t count, loff_t off) -{ - return off ? 0 : sprintf (page, "CHR\n"); -} -static DEVICE_ATTR(type,S_IRUGO,sr_device_type_read,NULL); - - void sr_finish() { int i; @@ -749,7 +739,7 @@ * with loadable modules. */ if (cd->disk) continue; - disk = alloc_disk(); + disk = alloc_disk(1); if (!disk) continue; if (cd->disk) { @@ -758,7 +748,6 @@ } disk->major = MAJOR_NR; disk->first_minor = i; - disk->minor_shift = 0; strcpy(disk->disk_name, cd->cdi.name); disk->fops = &sr_bdops; disk->flags = GENHD_FL_CD; @@ -790,22 +779,8 @@ */ get_capabilities(cd); sr_vendor_init(cd); - - sprintf(cd->cdi.cdrom_driverfs_dev.bus_id, "%s:cd", - cd->device->sdev_driverfs_dev.bus_id); - sprintf(cd->cdi.cdrom_driverfs_dev.name, "%scdrom", - cd->device->sdev_driverfs_dev.name); - cd->cdi.cdrom_driverfs_dev.parent = - &cd->device->sdev_driverfs_dev; - cd->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type; - cd->cdi.cdrom_driverfs_dev.driver_data = - (void *)(long)__mkdev(MAJOR_NR, i); - device_register(&cd->cdi.cdrom_driverfs_dev); - device_create_file(&cd->cdi.cdrom_driverfs_dev, - &dev_attr_type); - device_create_file(&cd->cdi.cdrom_driverfs_dev, - &dev_attr_kdev); disk->de = cd->device->de; + disk->driverfs_dev = &cd->device->sdev_driverfs_dev; register_cdrom(&cd->cdi); set_capacity(disk, cd->capacity); add_disk(disk); diff -Nru a/drivers/scsi/sr.h b/drivers/scsi/sr.h --- a/drivers/scsi/sr.h Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/sr.h Tue Oct 15 20:29:16 2002 @@ -20,6 +20,10 @@ #include "scsi.h" #include +/* The CDROM is fairly slow, so we need a little extra time */ +/* In fact, it is very slow if it has to spin up first */ +#define IOCTL_TIMEOUT 30*HZ + typedef struct { unsigned capacity; /* size in blocks */ Scsi_Device *device; @@ -34,7 +38,7 @@ struct gendisk *disk; } Scsi_CD; -int sr_do_ioctl(Scsi_CD *, unsigned char *, void *, unsigned, int, int, struct request_sense *); +int sr_do_ioctl(Scsi_CD *, struct cdrom_generic_command *); int sr_lock_door(struct cdrom_device_info *, int); int sr_tray_move(struct cdrom_device_info *, int); diff -Nru a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c --- a/drivers/scsi/sr_ioctl.c Tue Oct 15 20:29:17 2002 +++ b/drivers/scsi/sr_ioctl.c Tue Oct 15 20:29:17 2002 @@ -25,9 +25,6 @@ static int xa_test = 0; #define IOCTL_RETRIES 3 -/* The CDROM is fairly slow, so we need a little extra time */ -/* In fact, it is very slow if it has to spin up first */ -#define IOCTL_TIMEOUT 30*HZ /* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command. When these drives are emulating a SCSI device via the idescsi module, they need to have @@ -37,7 +34,7 @@ { struct cdrom_tocentry trk0_te, trk1_te; struct cdrom_tochdr tochdr; - u_char sr_cmd[10]; + struct cdrom_generic_command cgc; int ntracks, ret; if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr))) @@ -59,22 +56,25 @@ return ret; if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te))) return ret; - - sr_cmd[0] = GPCMD_PLAY_AUDIO_MSF; - sr_cmd[3] = trk0_te.cdte_addr.msf.minute; - sr_cmd[4] = trk0_te.cdte_addr.msf.second; - sr_cmd[5] = trk0_te.cdte_addr.msf.frame; - sr_cmd[6] = trk1_te.cdte_addr.msf.minute; - sr_cmd[7] = trk1_te.cdte_addr.msf.second; - sr_cmd[8] = trk1_te.cdte_addr.msf.frame; - return sr_do_ioctl(cdi->handle, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; + cgc.cmd[3] = trk0_te.cdte_addr.msf.minute; + cgc.cmd[4] = trk0_te.cdte_addr.msf.second; + cgc.cmd[5] = trk0_te.cdte_addr.msf.frame; + cgc.cmd[6] = trk1_te.cdte_addr.msf.minute; + cgc.cmd[7] = trk1_te.cdte_addr.msf.second; + cgc.cmd[8] = trk1_te.cdte_addr.msf.frame; + cgc.data_direction = SCSI_DATA_NONE; + cgc.timeout = IOCTL_TIMEOUT; + return sr_do_ioctl(cdi->handle, &cgc); } /* We do our own retries because we want to know what the specific error code is. Normally the UNIT_ATTENTION code will automatically clear after one error */ -int sr_do_ioctl(Scsi_CD *cd, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite, struct request_sense *sense) +int sr_do_ioctl(Scsi_CD *cd, struct cdrom_generic_command *cgc) { Scsi_Request *SRpnt; Scsi_Device *SDev; @@ -86,29 +86,32 @@ SRpnt = scsi_allocate_request(SDev); if (!SRpnt) { printk("Unable to allocate SCSI request in sr_do_ioctl"); - return -ENOMEM; + err = -ENOMEM; + goto out; } - SRpnt->sr_data_direction = readwrite; + SRpnt->sr_data_direction = cgc->data_direction; /* use ISA DMA buffer if necessary */ - SRpnt->sr_request->buffer = buffer; - if (buffer && SRpnt->sr_host->unchecked_isa_dma && - (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) { - bounce_buffer = (char *) kmalloc(buflength, GFP_DMA); + SRpnt->sr_request->buffer = cgc->buffer; + if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma && + (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) { + bounce_buffer = (char *) kmalloc(cgc->buflen, GFP_DMA); if (bounce_buffer == NULL) { printk("SCSI DMA pool exhausted."); - return -ENOMEM; + err = -ENOMEM; + goto out; } - memcpy(bounce_buffer, (char *) buffer, buflength); - buffer = bounce_buffer; + memcpy(bounce_buffer, cgc->buffer, cgc->buflen); + cgc->buffer = bounce_buffer; } retry: - if (!scsi_block_when_processing_errors(SDev)) - return -ENODEV; - + if (!scsi_block_when_processing_errors(SDev)) { + err = -ENODEV; + goto out; + } - scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength, - IOCTL_TIMEOUT, IOCTL_RETRIES); + scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen, + cgc->timeout, IOCTL_RETRIES); req = SRpnt->sr_request; if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { @@ -124,7 +127,7 @@ switch (SRpnt->sr_sense_buffer[2] & 0xf) { case UNIT_ATTENTION: SDev->changed = 1; - if (!quiet) + if (!cgc->quiet) printk(KERN_INFO "%s: disc change detected.\n", cd->cdi.name); if (retries++ < 10) goto retry; @@ -134,7 +137,7 @@ if (SRpnt->sr_sense_buffer[12] == 0x04 && SRpnt->sr_sense_buffer[13] == 0x01) { /* sense: Logical unit is in process of becoming ready */ - if (!quiet) + if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); if (retries++ < 10) { /* sleep 2 sec and try again */ @@ -146,7 +149,7 @@ break; } } - if (!quiet) + if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name); #ifdef DEBUG print_req_sense("sr", SRpnt); @@ -154,7 +157,7 @@ err = -ENOMEDIUM; break; case ILLEGAL_REQUEST: - if (!quiet) + if (!cgc->quiet) printk(KERN_ERR "%s: CDROM (ioctl) reports ILLEGAL " "REQUEST.\n", cd->cdi.name); if (SRpnt->sr_sense_buffer[12] == 0x20 && @@ -165,24 +168,26 @@ err = -EINVAL; } #ifdef DEBUG - print_command(sr_cmd); + print_command(cgc->cmd); print_req_sense("sr", SRpnt); #endif break; default: printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name); - print_command(sr_cmd); + print_command(cgc->cmd); print_req_sense("sr", SRpnt); err = -EIO; } } - if (sense) - memcpy(sense, SRpnt->sr_sense_buffer, sizeof(*sense)); + if (cgc->sense) + memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense)); /* Wake up a process waiting for device */ scsi_release_request(SRpnt); SRpnt = NULL; + out: + cgc->stat = err; return err; } @@ -191,35 +196,39 @@ static int test_unit_ready(Scsi_CD *cd) { - u_char sr_cmd[10]; + struct cdrom_generic_command cgc; - sr_cmd[0] = GPCMD_TEST_UNIT_READY; - sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; - sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - return sr_do_ioctl(cd, sr_cmd, NULL, 0, 1, SCSI_DATA_NONE, NULL); + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = GPCMD_TEST_UNIT_READY; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + ((cd->device->lun) << 5) : 0; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_NONE; + cgc.timeout = IOCTL_TIMEOUT; + return sr_do_ioctl(cd, &cgc); } int sr_tray_move(struct cdrom_device_info *cdi, int pos) { Scsi_CD *cd = cdi->handle; - u_char sr_cmd[10]; - - sr_cmd[0] = GPCMD_START_STOP_UNIT; - sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; - sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; - sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; + struct cdrom_generic_command cgc; - return sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = GPCMD_START_STOP_UNIT; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + ((cd->device->lun) << 5) : 0; + cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; + cgc.data_direction = SCSI_DATA_NONE; + cgc.timeout = IOCTL_TIMEOUT; + return sr_do_ioctl(cd, &cgc); } int sr_lock_door(struct cdrom_device_info *cdi, int lock) { Scsi_CD *cd = cdi->handle; - return scsi_ioctl(cd->device, lock ? SCSI_IOCTL_DOORLOCK : - SCSI_IOCTL_DOORUNLOCK, 0); + return scsi_set_medium_removal(cd->device, lock ? + SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); } int sr_drive_status(struct cdrom_device_info *cdi, int slot) @@ -278,22 +287,22 @@ int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) { Scsi_CD *cd = cdi->handle; - u_char sr_cmd[10]; + struct cdrom_generic_command cgc; char buffer[32]; int result; - sr_cmd[0] = GPCMD_READ_SUBCHANNEL; - sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; - sr_cmd[2] = 0x40; /* I do want the subchannel info */ - sr_cmd[3] = 0x02; /* Give me medium catalog number info */ - sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[6] = 0; - sr_cmd[7] = 0; - sr_cmd[8] = 24; - sr_cmd[9] = 0; - - result = sr_do_ioctl(cd, sr_cmd, buffer, 24, 0, SCSI_DATA_READ, NULL); + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + ((cd->device->lun) << 5) : 0; + cgc.cmd[2] = 0x40; /* I do want the subchannel info */ + cgc.cmd[3] = 0x02; /* Give me medium catalog number info */ + cgc.cmd[8] = 24; + cgc.buffer = buffer; + cgc.buflen = 24; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = IOCTL_TIMEOUT; + result = sr_do_ioctl(cd, &cgc); memcpy(mcn->medium_catalog_number, buffer + 9, 13); mcn->medium_catalog_number[13] = 0; @@ -309,21 +318,23 @@ int sr_select_speed(struct cdrom_device_info *cdi, int speed) { Scsi_CD *cd = cdi->handle; - u_char sr_cmd[MAX_COMMAND_SIZE]; + struct cdrom_generic_command cgc; if (speed == 0) speed = 0xffff; /* set to max */ else speed *= 177; /* Nx to kbyte/s */ - memset(sr_cmd, 0, MAX_COMMAND_SIZE); - sr_cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ - sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; - sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ - sr_cmd[3] = speed & 0xff; /* LSB */ + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + ((cd->device->lun) << 5) : 0; + cgc.cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ + cgc.cmd[3] = speed & 0xff; /* LSB */ + cgc.data_direction = SCSI_DATA_NONE; + cgc.timeout = IOCTL_TIMEOUT; - if (sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL)) + if (sr_do_ioctl(cd, &cgc)) return -EIO; return 0; } @@ -337,24 +348,28 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) { Scsi_CD *cd = cdi->handle; - u_char sr_cmd[10]; + struct cdrom_generic_command cgc; int result; unsigned char buffer[32]; - memset(sr_cmd, 0, sizeof(sr_cmd)); + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.timeout = IOCTL_TIMEOUT; switch (cmd) { case CDROMREADTOCHDR: { struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg; - sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; - sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[8] = 12; /* LSB of length */ + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + ((cd->device->lun) << 5) : 0; + cgc.cmd[8] = 12; /* LSB of length */ + cgc.buffer = buffer; + cgc.buflen = 12; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_READ; - result = sr_do_ioctl(cd, sr_cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); + result = sr_do_ioctl(cd, &cgc); tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; @@ -366,15 +381,17 @@ { struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg; - sr_cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - ((cd->device->lun) << 5) : 0; - sr_cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; - sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - sr_cmd[6] = tocentry->cdte_track; - sr_cmd[8] = 12; /* LSB of length */ + cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + ((cd->device->lun) << 5) : 0; + cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; + cgc.cmd[6] = tocentry->cdte_track; + cgc.cmd[8] = 12; /* LSB of length */ + cgc.buffer = buffer; + cgc.buflen = 12; + cgc.data_direction = SCSI_DATA_READ; - result = sr_do_ioctl(cd, sr_cmd, buffer, 12, 0, SCSI_DATA_READ, NULL); + result = sr_do_ioctl(cd, &cgc); tocentry->cdte_ctrl = buffer[5] & 0xf; tocentry->cdte_adr = buffer[5] >> 4; @@ -393,15 +410,16 @@ case CDROMPLAYTRKIND: { struct cdrom_ti* ti = (struct cdrom_ti*)arg; - sr_cmd[0] = GPCMD_PLAYAUDIO_TI; - sr_cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - sr_cmd[4] = ti->cdti_trk0; - sr_cmd[5] = ti->cdti_ind0; - sr_cmd[7] = ti->cdti_trk1; - sr_cmd[8] = ti->cdti_ind1; + cgc.cmd[0] = GPCMD_PLAYAUDIO_TI; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[4] = ti->cdti_trk0; + cgc.cmd[5] = ti->cdti_ind0; + cgc.cmd[7] = ti->cdti_trk1; + cgc.cmd[8] = ti->cdti_ind1; + cgc.data_direction = SCSI_DATA_NONE; - result = sr_do_ioctl(cd, sr_cmd, NULL, 0, 0, SCSI_DATA_NONE, NULL); + result = sr_do_ioctl(cd, &cgc); if (result == -EDRIVE_CANT_DO_THIS) result = sr_fake_playtrkind(cdi, ti); @@ -436,38 +454,42 @@ static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize) { - unsigned char cmd[MAX_COMMAND_SIZE]; + struct cdrom_generic_command cgc; #ifdef DEBUG printk("%s: sr_read_cd lba=%d format=%d blksize=%d\n", cd->cdi.name, lba, format, blksize); #endif - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = GPCMD_READ_CD; /* READ_CD */ - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[1] |= ((format & 7) << 2); - cmd[2] = (unsigned char) (lba >> 24) & 0xff; - cmd[3] = (unsigned char) (lba >> 16) & 0xff; - cmd[4] = (unsigned char) (lba >> 8) & 0xff; - cmd[5] = (unsigned char) lba & 0xff; - cmd[8] = 1; + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = GPCMD_READ_CD; /* READ_CD */ + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[1] |= ((format & 7) << 2); + cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; + cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; + cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; + cgc.cmd[5] = (unsigned char) lba & 0xff; + cgc.cmd[8] = 1; switch (blksize) { case 2336: - cmd[9] = 0x58; + cgc.cmd[9] = 0x58; break; case 2340: - cmd[9] = 0x78; + cgc.cmd[9] = 0x78; break; case 2352: - cmd[9] = 0xf8; + cgc.cmd[9] = 0xf8; break; default: - cmd[9] = 0x10; + cgc.cmd[9] = 0x10; break; } - return sr_do_ioctl(cd, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL); + cgc.buffer = dest; + cgc.buflen = blksize; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = IOCTL_TIMEOUT; + return sr_do_ioctl(cd, &cgc); } /* @@ -476,7 +498,7 @@ static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest) { - unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */ + struct cdrom_generic_command cgc; int rc; /* we try the READ CD command first... */ @@ -497,16 +519,20 @@ printk("%s: sr_read_sector lba=%d blksize=%d\n", cd->cdi.name, lba, blksize); #endif - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = GPCMD_READ_10; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[2] = (unsigned char) (lba >> 24) & 0xff; - cmd[3] = (unsigned char) (lba >> 16) & 0xff; - cmd[4] = (unsigned char) (lba >> 8) & 0xff; - cmd[5] = (unsigned char) lba & 0xff; - cmd[8] = 1; - rc = sr_do_ioctl(cd, cmd, dest, blksize, 0, SCSI_DATA_READ, NULL); + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = GPCMD_READ_10; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; + cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; + cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; + cgc.cmd[5] = (unsigned char) lba & 0xff; + cgc.cmd[8] = 1; + cgc.buffer = dest; + cgc.buflen = blksize; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = IOCTL_TIMEOUT; + rc = sr_do_ioctl(cd, &cgc); return rc; } @@ -562,7 +588,6 @@ * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 - * indent-tabs-mode: nil * tab-width: 8 * End: */ diff -Nru a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c --- a/drivers/scsi/sr_vendor.c Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/sr_vendor.c Tue Oct 15 20:29:16 2002 @@ -58,6 +58,8 @@ #define VENDOR_TOSHIBA 3 #define VENDOR_WRITER 4 /* pre-scsi3 writers */ +#define VENDOR_TIMEOUT 30*HZ + void sr_vendor_init(Scsi_CD *cd) { #ifndef CONFIG_BLK_DEV_SR_VENDOR @@ -104,7 +106,7 @@ int sr_set_blocklength(Scsi_CD *cd, int blocklength) { unsigned char *buffer; /* the buffer for the ioctl */ - unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */ + struct cdrom_generic_command cgc; struct ccs_modesel_head *modesel; int rc, density = 0; @@ -120,19 +122,23 @@ #ifdef DEBUG printk("%s: MODE SELECT 0x%x/%d\n", cd->cdi.name, density, blocklength); #endif - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[1] |= (1 << 4); - cmd[4] = 12; + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + cgc.cmd[0] = MODE_SELECT; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[1] |= (1 << 4); + cgc.cmd[4] = 12; modesel = (struct ccs_modesel_head *) buffer; memset(modesel, 0, sizeof(*modesel)); modesel->block_desc_length = 0x08; modesel->density = density; modesel->block_length_med = (blocklength >> 8) & 0xff; modesel->block_length_lo = blocklength & 0xff; - if (0 == (rc = sr_do_ioctl(cd, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE, NULL))) { + cgc.buffer = buffer; + cgc.buflen = sizeof(*modesel); + cgc.data_direction = SCSI_DATA_WRITE; + cgc.timeout = VENDOR_TIMEOUT; + if (0 == (rc = sr_do_ioctl(cd, &cgc))) { cd->device->sector_size = blocklength; } #ifdef DEBUG @@ -154,7 +160,7 @@ Scsi_CD *cd = cdi->handle; unsigned long sector; unsigned char *buffer; /* the buffer for the ioctl */ - unsigned char cmd[MAX_COMMAND_SIZE]; /* the scsi-command */ + struct cdrom_generic_command cgc; int rc, no_multi; if (cd->cdi.mask & CDC_MULTI_SESSION) @@ -168,16 +174,22 @@ no_multi = 0; /* flag: the drive can't handle multisession */ rc = 0; + memset(&cgc, 0, sizeof(struct cdrom_generic_command)); + switch (cd->vendor) { case VENDOR_SCSI3: - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_TOC; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[8] = 12; - cmd[9] = 0x40; - rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); + cgc.cmd[0] = READ_TOC; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[8] = 12; + cgc.cmd[9] = 0x40; + cgc.buffer = buffer; + cgc.buflen = 12; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = VENDOR_TIMEOUT; + rc = sr_do_ioctl(cd, &cgc); if (rc != 0) break; if ((buffer[0] << 8) + buffer[1] < 0x0a) { @@ -197,13 +209,17 @@ #ifdef CONFIG_BLK_DEV_SR_VENDOR case VENDOR_NEC:{ unsigned long min, sec, frame; - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = 0xde; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[1] |= 0x03; - cmd[2] = 0xb0; - rc = sr_do_ioctl(cd, cmd, buffer, 0x16, 1, SCSI_DATA_READ, NULL); + cgc.cmd[0] = 0xde; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[1] |= 0x03; + cgc.cmd[2] = 0xb0; + cgc.buffer = buffer; + cgc.buflen = 0x16; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = VENDOR_TIMEOUT; + rc = sr_do_ioctl(cd, &cgc); if (rc != 0) break; if (buffer[14] != 0 && buffer[14] != 0xb0) { @@ -225,12 +241,16 @@ /* we request some disc information (is it a XA-CD ?, * where starts the last session ?) */ - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = 0xc7; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[1] |= 0x03; - rc = sr_do_ioctl(cd, cmd, buffer, 4, 1, SCSI_DATA_READ, NULL); + cgc.cmd[0] = 0xc7; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[1] |= 0x03; + cgc.buffer = buffer; + cgc.buflen = 4; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = VENDOR_TIMEOUT; + rc = sr_do_ioctl(cd, &cgc); if (rc == -EINVAL) { printk(KERN_INFO "%s: Hmm, seems the drive " "doesn't support multisession CD's\n", @@ -251,13 +271,17 @@ } case VENDOR_WRITER: - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_TOC; - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[8] = 0x04; - cmd[9] = 0x40; - rc = sr_do_ioctl(cd, cmd, buffer, 0x04, 1, SCSI_DATA_READ, NULL); + cgc.cmd[0] = READ_TOC; + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[8] = 0x04; + cgc.cmd[9] = 0x40; + cgc.buffer = buffer; + cgc.buflen = 0x04; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = VENDOR_TIMEOUT; + rc = sr_do_ioctl(cd, &cgc); if (rc != 0) { break; } @@ -266,13 +290,18 @@ "%s: No finished session\n", cd->cdi.name); break; } - cmd[0] = READ_TOC; /* Read TOC */ - cmd[1] = (cd->device->scsi_level <= SCSI_2) ? - (cd->device->lun << 5) : 0; - cmd[6] = rc & 0x7f; /* number of last session */ - cmd[8] = 0x0c; - cmd[9] = 0x40; - rc = sr_do_ioctl(cd, cmd, buffer, 12, 1, SCSI_DATA_READ, NULL); + cgc.cmd[0] = READ_TOC; /* Read TOC */ + cgc.cmd[1] = (cd->device->scsi_level <= SCSI_2) ? + (cd->device->lun << 5) : 0; + cgc.cmd[6] = rc & 0x7f; /* number of last session */ + cgc.cmd[8] = 0x0c; + cgc.cmd[9] = 0x40; + cgc.buffer = buffer; + cgc.buflen = 12; + cgc.quiet = 1; + cgc.data_direction = SCSI_DATA_READ; + cgc.timeout = VENDOR_TIMEOUT; + rc = sr_do_ioctl(cd, &cgc); if (rc != 0) { break; } diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Tue Oct 15 20:29:17 2002 +++ b/drivers/scsi/st.c Tue Oct 15 20:29:17 2002 @@ -12,13 +12,13 @@ Copyright 1992 - 2002 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Sun Sep 29 22:29:16 2002 by makisara + Last modified: Tue Oct 15 22:01:04 2002 by makisara Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20020929"; +static char *verstr = "20021015"; #include @@ -291,6 +291,8 @@ if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */ STp->cleaning_req = 1; + STp->pos_unknown |= STp->device->was_reset; + if ((sense[0] & 0x70) == 0x70 && scode == RECOVERED_ERROR #if ST_RECOVERED_WRITE_FATAL @@ -566,7 +568,7 @@ * If there was a bus reset, block further access * to this device. */ - if (STp->device->was_reset) + if (STp->pos_unknown) return (-EIO); if (STp->ready != ST_READY) @@ -640,6 +642,52 @@ } return 0; } + + +/* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */ +static int do_door_lock(Scsi_Tape * STp, int do_lock) +{ + int retval, cmd; + DEB(int dev = TAPE_NR(STp->devt);) + + + cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK; + DEBC(printk(ST_DEB_MSG "st%d: %socking drive door.\n", dev, + do_lock ? "L" : "Unl")); + retval = scsi_ioctl(STp->device, cmd, NULL); + if (!retval) { + STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; + } + else { + STp->door_locked = ST_LOCK_FAILS; + } + return retval; +} + + +/* Set the internal state after reset */ +static void reset_state(Scsi_Tape *STp) +{ + int i; + ST_partstat *STps; + + STp->pos_unknown = 0; + for (i = 0; i < ST_NBR_PARTITIONS; i++) { + STps = &(STp->ps[i]); + STps->rw = ST_IDLE; + STps->eof = ST_NOEOF; + STps->at_sm = 0; + STps->last_block_valid = FALSE; + STps->drv_block = -1; + STps->drv_file = -1; + } + if (STp->can_partitions) { + STp->partition = find_partition(STp); + if (STp->partition < 0) + STp->partition = 0; + STp->new_partition = STp->partition; + } +} /* Test if the drive is ready. Returns either one of the codes below or a negative system error code. */ @@ -757,7 +805,7 @@ goto err_out; if (retval == CHKRES_NEW_SESSION) { - (STp->device)->was_reset = 0; + STp->pos_unknown = 0; STp->partition = STp->new_partition = 0; if (STp->can_partitions) STp->nbr_partitions = 1; /* This guess will be updated later @@ -1021,7 +1069,7 @@ STm = &(STp->modes[STp->current_mode]); STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { + if (STps->rw == ST_WRITING && !STp->pos_unknown) { result = flush_write_buffer(STp); if (result != 0 && result != (-ENOSPC)) goto out; @@ -1040,7 +1088,7 @@ printk(KERN_WARNING "st%d: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", dev, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable)); - if (STps->rw == ST_WRITING && !(STp->device)->was_reset) { + if (STps->rw == ST_WRITING && !STp->pos_unknown) { DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n", dev, (long) (filp->f_pos)); @@ -1136,7 +1184,7 @@ read_unlock(&st_dev_arr_lock); if (STp->door_locked == ST_LOCKED_AUTO) - st_int_ioctl(STp, MTUNLOCK, 0); + do_door_lock(STp, 0); normalize_buffer(STp->buffer); write_lock(&st_dev_arr_lock); @@ -1189,7 +1237,7 @@ * If there was a bus reset, block further access * to this device. */ - if (STp->device->was_reset) { + if (STp->pos_unknown) { retval = (-EIO); goto out; } @@ -1216,7 +1264,7 @@ } if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && - !st_int_ioctl(STp, MTLOCK, 0)) + !do_door_lock(STp, 1)) STp->door_locked = ST_LOCKED_AUTO; out: @@ -2502,18 +2550,6 @@ DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev)); fileno = blkno = at_sm = 0; break; - case MTLOCK: - chg_eof = FALSE; - cmd[0] = ALLOW_MEDIUM_REMOVAL; - cmd[4] = SCSI_REMOVAL_PREVENT; - DEBC(printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev)); - break; - case MTUNLOCK: - chg_eof = FALSE; - cmd[0] = ALLOW_MEDIUM_REMOVAL; - cmd[4] = SCSI_REMOVAL_ALLOW; - DEBC(printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev)); - break; case MTSETBLK: /* Set block length */ case MTSETDENSITY: /* Set tape density */ case MTSETDRVBUFFER: /* Set drive buffering */ @@ -2594,11 +2630,6 @@ STps->drv_file = fileno; STps->at_sm = at_sm; - if (cmd_in == MTLOCK) - STp->door_locked = ST_LOCKED_EXPLICIT; - else if (cmd_in == MTUNLOCK) - STp->door_locked = ST_UNLOCKED; - if (cmd_in == MTBSFM) ioctl_result = st_int_ioctl(STp, MTFSF, 1); else if (cmd_in == MTFSFM) @@ -2713,9 +2744,6 @@ if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) STps->eof = ST_EOD; - if (cmd_in == MTLOCK) - STp->door_locked = ST_LOCK_FAILS; - scsi_release_request(SRpnt); SRpnt = NULL; } @@ -3104,7 +3132,7 @@ goto out; } - if (!(STp->device)->was_reset) { + if (!STp->pos_unknown) { if (STps->eof == ST_FM_HIT) { if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || @@ -3152,16 +3180,9 @@ retval = (-EIO); goto out; } + reset_state(STp); + /* remove this when the midlevel properly clears was_reset */ STp->device->was_reset = 0; - if (STp->door_locked != ST_UNLOCKED && - STp->door_locked != ST_LOCK_FAILS) { - if (st_int_ioctl(STp, MTLOCK, 0)) { - printk(KERN_NOTICE - "st%d: Could not relock door after bus reset.\n", - dev); - STp->door_locked = ST_UNLOCKED; - } - } } if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && @@ -3170,7 +3191,7 @@ STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) - st_int_ioctl(STp, MTUNLOCK, 0); /* Ignore result! */ + do_door_lock(STp, 0); /* Ignore result! */ if (mtc.mt_op == MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) != 0) { @@ -3238,6 +3259,11 @@ goto out; } + if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) { + retval = do_door_lock(STp, (mtc.mt_op == MTLOCK)); + goto out; + } + if (STp->can_partitions && STp->ready == ST_READY && (i = switch_partition(STp)) < 0) { retval = i; @@ -3642,13 +3668,13 @@ static struct file_operations st_fops = { - owner: THIS_MODULE, - read: st_read, - write: st_write, - ioctl: st_ioctl, - open: st_open, - flush: st_flush, - release: st_release, + .owner = THIS_MODULE, + .read = st_read, + .write = st_write, + .ioctl = st_ioctl, + .open = st_open, + .flush = st_flush, + .release = st_release, }; static int st_attach(Scsi_Device * SDp) @@ -3909,12 +3935,12 @@ &dev_attr_type); device_remove_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev); - put_device(&tpnt->driverfs_dev_r[mode]); + device_unregister(&tpnt->driverfs_dev_r[mode]); device_remove_file(&tpnt->driverfs_dev_n[mode], &dev_attr_type); device_remove_file(&tpnt->driverfs_dev_n[mode], &dev_attr_kdev); - put_device(&tpnt->driverfs_dev_n[mode]); + device_unregister(&tpnt->driverfs_dev_n[mode]); } if (tpnt->buffer) { tpnt->buffer->orig_frp_segs = 0; diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h --- a/drivers/scsi/st.h Tue Oct 15 20:29:20 2002 +++ b/drivers/scsi/st.h Tue Oct 15 20:29:20 2002 @@ -94,6 +94,7 @@ unsigned char use_pf; /* Set Page Format bit in all mode selects? */ unsigned char try_dio; /* try direct i/o? */ unsigned char c_algo; /* compression algorithm */ + unsigned char pos_unknown; /* after reset position unknown */ int tape_type; int write_threshold; int timeout; /* timeout for normal commands */ diff -Nru a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c --- a/drivers/scsi/sym53c416.c Tue Oct 15 20:29:12 2002 +++ b/drivers/scsi/sym53c416.c Tue Oct 15 20:29:12 2002 @@ -9,6 +9,8 @@ * Alan Cox : Cleaned up code formatting * Fixed an irq locking bug * Added ISAPnP support + * Bjoern A. Zeeb : Initial irq locking updates + * Added another card with ISAPnP support * * LILO command line usage: sym53c416=[,] * @@ -27,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -194,18 +197,10 @@ #endif -/* #define DEBUG */ - -/* Macro for debugging purposes */ - -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - #define MAXHOSTS 4 +#define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset)) + enum phases { idle, @@ -246,6 +241,8 @@ outb((len & 0xFF0000) >> 16, base + TC_HIGH); } +static spinlock_t sym53c416_lock = SPIN_LOCK_UNLOCKED; + /* Returns the number of bytes read */ static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len) { @@ -256,8 +253,7 @@ int timeout = READ_TIMEOUT; /* Do transfer */ - save_flags(flags); - cli(); + spin_lock_irqsave(&sym53c416_lock, flags); while(len && timeout) { bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */ @@ -276,17 +272,16 @@ else { i = jiffies + timeout; - restore_flags(flags); + spin_unlock_irqrestore(&sym53c416_lock, flags); while(jiffies < i && (inb(base + PIO_INT_REG) & EMPTY) && timeout) if(inb(base + PIO_INT_REG) & SCI) timeout = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&sym53c416_lock, flags); if(inb(base + PIO_INT_REG) & EMPTY) timeout = 0; } } - restore_flags(flags); + spin_unlock_irqrestore(&sym53c416_lock, flags); return orig_len - len; } @@ -300,8 +295,7 @@ unsigned int timeout = WRITE_TIMEOUT; /* Do transfer */ - save_flags(flags); - cli(); + spin_lock_irqsave(&sym53c416_lock, flags); while(len && timeout) { bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT); @@ -322,16 +316,15 @@ else { i = jiffies + timeout; - restore_flags(flags); + spin_unlock_irqrestore(&sym53c416_lock, flags); while(jiffies < i && (inb(base + PIO_INT_REG) & FULL) && timeout) ; - save_flags(flags); - cli(); + spin_lock_irqsave(&sym53c416_lock, flags); if(inb(base + PIO_INT_REG) & FULL) timeout = 0; } } - restore_flags(flags); + spin_unlock_irqrestore(&sym53c416_lock, flags); return orig_len - len; } @@ -449,7 +442,7 @@ sglist = current_command->request_buffer; while(sgcount--) { - tot_trans += sym53c416_write(base, sglist->address, sglist->length); + tot_trans += sym53c416_write(base, SG_ADDRESS(sglist), sglist->length); sglist++; } } @@ -475,7 +468,7 @@ sglist = current_command->request_buffer; while(sgcount--) { - tot_trans += sym53c416_read(base, sglist->address, sglist->length); + tot_trans += sym53c416_read(base, SG_ADDRESS(sglist), sglist->length); sglist++; } } @@ -562,7 +555,7 @@ i = jiffies + 20; while(i > jiffies && !(inb(base + STATUS_REG) & SCI)) barrier(); - if(i <= jiffies) /* timed out */ + if(time_before_eq(i, jiffies)) /* timed out */ return 0; /* Get occurred irq */ irq = probe_irq_off(irqs); @@ -611,10 +604,12 @@ } -static struct isapnp_device_id id_table[] = { +static struct isapnp_device_id id_table[] __devinitdata = { + { ISAPNP_ANY_ID, ISAPNP_ANY_ID, + ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4161), 0 }, { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 }, - {0} + { ISAPNP_DEVICE_SINGLE_END } }; MODULE_DEVICE_TABLE(isapnp, id_table); @@ -635,7 +630,7 @@ } } -int sym53c416_detect(Scsi_Host_Template *tpnt) +int __init sym53c416_detect(Scsi_Host_Template *tpnt) { unsigned long flags; struct Scsi_Host * shpnt = NULL; @@ -674,29 +669,32 @@ #endif printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING); - while((idev=isapnp_find_dev(NULL, ISAPNP_VENDOR('S','L','I'), - ISAPNP_FUNCTION(0x4163), idev))!=NULL) - { - int i[3]; - - if(idev->prepare(idev)<0) - { - printk(KERN_WARNING "sym53c416: unable to prepare PnP card.\n"); - continue; - } - if(idev->activate(idev)<0) + for (i=0; id_table[i].vendor != 0; i++) { + while((idev=isapnp_find_dev(NULL, id_table[i].vendor, + id_table[i].function, idev))!=NULL) { - printk(KERN_WARNING "sym53c416: unable to activate PnP card.\n"); - continue; - } - - i[0] = 2; - i[1] = idev->resource[0].start; - i[2] = idev->irq_resource[0].start; - - printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n", - i[1], i[2]); - sym53c416_setup(NULL, i); + int i[3]; + + if(idev->prepare(idev)<0) + { + printk(KERN_WARNING "sym53c416: unable to prepare PnP card.\n"); + continue; + } + if(idev->activate(idev)<0) + { + printk(KERN_WARNING "sym53c416: unable to activate PnP card.\n"); + continue; + + } + + i[0] = 2; + i[1] = idev->resource[0].start; + i[2] = idev->irq_resource[0].start; + + printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n", + i[1], i[2]); + sym53c416_setup(NULL, i); + } } sym53c416_probe(); @@ -716,13 +714,12 @@ shpnt = scsi_register(tpnt, 0); if(shpnt==NULL) continue; - save_flags(flags); - cli(); + spin_lock_irqsave(&sym53c416_lock, flags); /* FIXME: Request_irq with CLI is not safe */ /* Request for specified IRQ */ if(request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt)) { - restore_flags(flags); + spin_unlock_irqrestore(&sym53c416_lock, flags); printk(KERN_ERR "sym53c416: Unable to assign IRQ %d\n", hosts[i].irq); scsi_unregister(shpnt); } @@ -737,7 +734,7 @@ shpnt->this_id = hosts[i].scsi_id; sym53c416_init(hosts[i].base, hosts[i].scsi_id); count++; - restore_flags(flags); + spin_unlock_irqrestore(&sym53c416_lock, flags); } } } @@ -774,8 +771,7 @@ current_command->SCp.Status = 0; current_command->SCp.Message = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&sym53c416_lock, flags); outb(SCpnt->target, base + DEST_BUS_ID); /* Set scsi id target */ outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */ /* Write SCSI command into the SCSI fifo */ @@ -784,7 +780,7 @@ /* Start selection sequence */ outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG); /* Now an interrupt will be generated which we will catch in out interrupt routine */ - restore_flags(flags); + spin_unlock_irqrestore(&sym53c416_lock, flags); return 0; } @@ -804,7 +800,7 @@ static int sym53c416_abort(Scsi_Cmnd *SCpnt) { - //printk("sym53c416_abort\n"); + /* printk("sym53c416_abort\n"); */ /* We don't know how to abort for the moment */ return SCSI_ABORT_SNOOZE; } @@ -815,7 +811,7 @@ int scsi_id = -1; int i; - //printk("sym53c416_reset\n"); + /* printk("sym53c416_reset\n"); */ base = SCpnt->host->io_port; /* search scsi_id */ for(i = 0; i < host_index && scsi_id != -1; i++) diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c --- a/drivers/scsi/sym53c8xx.c Tue Oct 15 20:29:18 2002 +++ b/drivers/scsi/sym53c8xx.c Tue Oct 15 20:29:18 2002 @@ -1341,8 +1341,6 @@ #define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff) #endif -static void sym53c8xx_select_queue_depths( - struct Scsi_Host *host, struct scsi_device *devlist); static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); static void sym53c8xx_timeout(unsigned long np); @@ -5923,8 +5921,6 @@ #endif #endif - instance->select_queue_depths = sym53c8xx_select_queue_depths; - NCR_UNLOCK_NCB(np, flags); /* @@ -13545,56 +13541,57 @@ return DEF_DEPTH; } -static void sym53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist) +int sym53c8xx_slave_attach(Scsi_Device *device) { - struct scsi_device *device; - - for (device = devlist; device; device = device->next) { - ncb_p np; - tcb_p tp; - lcb_p lp; - int numtags; - - if (device->host != host) - continue; + struct Scsi_Host *host = device->host; + ncb_p np; + tcb_p tp; + lcb_p lp; + int numtags, depth_to_use; - np = ((struct host_data *) host->hostdata)->ncb; - tp = &np->target[device->id]; - lp = ncr_lp(np, tp, device->lun); - - /* - ** Select queue depth from driver setup. - ** Donnot use more than configured by user. - ** Use at least 2. - ** Donnot use more than our maximum. - */ - numtags = device_queue_depth(np, device->id, device->lun); - if (numtags > tp->usrtags) - numtags = tp->usrtags; - if (!device->tagged_supported) - numtags = 1; - device->queue_depth = numtags; - if (device->queue_depth < 2) - device->queue_depth = 2; - if (device->queue_depth > MAX_TAGS) - device->queue_depth = MAX_TAGS; - - /* - ** Since the queue depth is not tunable under Linux, - ** we need to know this value in order not to - ** announce stupid things to user. - */ - if (lp) { - lp->numtags = lp->maxtags = numtags; - lp->scdev_depth = device->queue_depth; - } - ncr_setup_tags (np, device->id, device->lun); + np = ((struct host_data *) host->hostdata)->ncb; + tp = &np->target[device->id]; + lp = ncr_lp(np, tp, device->lun); + + /* + ** Select queue depth from driver setup. + ** Donnot use more than configured by user. + ** Use at least 2. + ** Donnot use more than our maximum. + */ + numtags = device_queue_depth(np, device->id, device->lun); + if (numtags > tp->usrtags) + numtags = tp->usrtags; + if (!device->tagged_supported) + numtags = 1; + depth_to_use = numtags; + if (depth_to_use < 2) + depth_to_use = 2; + if (depth_to_use > MAX_TAGS) + depth_to_use = MAX_TAGS; + + scsi_adjust_queue_depth(device, + (device->tagged_supported ? + MSG_SIMPLE_TAG : 0), + depth_to_use); + + /* + ** Since the queue depth is not tunable under Linux, + ** we need to know this value in order not to + ** announce stupid things to user. + */ + if (lp) { + lp->numtags = lp->maxtags = numtags; + lp->scdev_depth = depth_to_use; + } + ncr_setup_tags (np, device->id, device->lun); #ifdef DEBUG_SYM53C8XX -printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", - np->unit, device->id, device->lun, device->queue_depth); + printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", + np->unit, device->id, device->lun, depth_to_use); #endif - } + + return 0; } /* diff -Nru a/drivers/scsi/sym53c8xx.h b/drivers/scsi/sym53c8xx.h --- a/drivers/scsi/sym53c8xx.h Tue Oct 15 20:29:16 2002 +++ b/drivers/scsi/sym53c8xx.h Tue Oct 15 20:29:16 2002 @@ -74,6 +74,7 @@ const char *sym53c8xx_info(struct Scsi_Host *host); int sym53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int sym53c8xx_reset(Scsi_Cmnd *, unsigned int); +int sym53c8xx_slave_attach(Scsi_Device *); #ifdef MODULE int sym53c8xx_release(struct Scsi_Host *); @@ -89,6 +90,7 @@ release: sym53c8xx_release, \ info: sym53c8xx_info, \ queuecommand: sym53c8xx_queue_command,\ + slave_attach: sym53c8xx_slave_attach, \ abort: sym53c8xx_abort, \ reset: sym53c8xx_reset, \ bios_param: scsicam_bios_param, \ diff -Nru a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h --- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h Tue Oct 15 20:29:23 2002 +++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h Tue Oct 15 20:29:23 2002 @@ -89,6 +89,8 @@ int sym53c8xx_eh_bus_reset_handler(Scsi_Cmnd *); int sym53c8xx_eh_host_reset_handler(Scsi_Cmnd *); +int sym53c8xx_slave_attach(Scsi_Device *); + #ifdef MODULE int sym53c8xx_release(struct Scsi_Host *); #else @@ -109,6 +111,7 @@ release: sym53c8xx_release, \ info: sym53c8xx_info, \ queuecommand: sym53c8xx_queue_command, \ + slave_attach: sym53c8xx_slave_attach, \ eh_abort_handler: sym53c8xx_eh_abort_handler, \ eh_device_reset_handler:sym53c8xx_eh_device_reset_handler, \ eh_bus_reset_handler: sym53c8xx_eh_bus_reset_handler, \ diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c --- a/drivers/scsi/sym53c8xx_2/sym_glue.c Tue Oct 15 20:29:23 2002 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c Tue Oct 15 20:29:23 2002 @@ -1327,66 +1327,63 @@ /* * Linux entry point for device queue sizing. */ -static void -sym53c8xx_select_queue_depths(struct Scsi_Host *host, - struct scsi_device *devlist) -{ - struct scsi_device *device; - - for (device = devlist; device; device = device->next) { - hcb_p np; - tcb_p tp; - lcb_p lp; - int reqtags; - - if (device->host != host) - continue; +int +sym53c8xx_slave_attach(Scsi_Device *device) +{ + struct Scsi_Host *host = device->host; + hcb_p np; + tcb_p tp; + lcb_p lp; + int reqtags, depth_to_use; - np = ((struct host_data *) host->hostdata)->ncb; - tp = &np->target[device->id]; + np = ((struct host_data *) host->hostdata)->ncb; + tp = &np->target[device->id]; - /* - * Get user settings for transfer parameters. - */ - tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16); - sym_update_trans_settings(np, tp); + /* + * Get user settings for transfer parameters. + */ + tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16); + sym_update_trans_settings(np, tp); - /* - * Allocate the LCB if not yet. - * If it fail, we may well be in the sh*t. :) - */ - lp = sym_alloc_lcb(np, device->id, device->lun); - if (!lp) { - device->queue_depth = 1; - continue; - } + /* + * Allocate the LCB if not yet. + * If it fail, we may well be in the sh*t. :) + */ + lp = sym_alloc_lcb(np, device->id, device->lun); + if (!lp) + return -ENOMEM; - /* - * Get user flags. - */ - lp->curr_flags = lp->user_flags; + /* + * Get user flags. + */ + lp->curr_flags = lp->user_flags; - /* - * Select queue depth from driver setup. - * Donnot use more than configured by user. - * Use at least 2. - * Donnot use more than our maximum. - */ - reqtags = device_queue_depth(np, device->id, device->lun); - if (reqtags > tp->usrtags) - reqtags = tp->usrtags; - if (!device->tagged_supported) - reqtags = 0; + /* + * Select queue depth from driver setup. + * Donnot use more than configured by user. + * Use at least 2. + * Donnot use more than our maximum. + */ + reqtags = device_queue_depth(np, device->id, device->lun); + if (reqtags > tp->usrtags) + reqtags = tp->usrtags; + if (!device->tagged_supported) + reqtags = 0; #if 1 /* Avoid to locally queue commands for no good reasons */ - if (reqtags > SYM_CONF_MAX_TAG) - reqtags = SYM_CONF_MAX_TAG; - device->queue_depth = reqtags ? reqtags : 2; -#else - device->queue_depth = reqtags ? SYM_CONF_MAX_TAG : 2; -#endif - lp->s.scdev_depth = device->queue_depth; - sym_tune_dev_queuing(np, device->id, device->lun, reqtags); - } + if (reqtags > SYM_CONF_MAX_TAG) + reqtags = SYM_CONF_MAX_TAG; + depth_to_use = (reqtags ? reqtags : 2); +#else + depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2); +#endif + scsi_adjust_queue_depth(device, + (device->tagged_supported ? + MSG_SIMPLE_TAG : 0), + depth_to_use); + lp->s.scdev_depth = depth_to_use; + sym_tune_dev_queuing(np, device->id, device->lun, reqtags); + + return 0; } /* @@ -2132,7 +2129,6 @@ #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) instance->max_cmd_len = 16; #endif - instance->select_queue_depths = sym53c8xx_select_queue_depths; instance->highmem_io = 1; SYM_UNLOCK_HCB(np, flags); diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c Tue Oct 15 20:29:12 2002 +++ b/drivers/serial/8250.c Tue Oct 15 20:29:12 2002 @@ -1885,7 +1885,7 @@ port.line = line; if (HIGH_BITS_OFFSET) - port.iobase |= req->port_high << HIGH_BITS_OFFSET; + port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET; /* * If a clock rate wasn't specified by the low level diff -Nru a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/serial/8250_acorn.c Tue Oct 15 20:29:25 2002 @@ -0,0 +1,150 @@ +/* + * linux/drivers/serial/acorn.c + * + * Copyright (C) 1996-2002 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_PORTS 3 + +struct serial_card_type { + unsigned int num_ports; + unsigned int baud_base; + int type; + int speed; + int offset[MAX_PORTS]; +}; + +struct serial_card_info { + unsigned int num_ports; + int ports[MAX_PORTS]; + unsigned long base[MAX_PORTS]; +}; + +static inline int serial_register_onedev(unsigned long port, int irq, unsigned int baud_base) +{ + struct serial_struct req; + + memset(&req, 0, sizeof(req)); + req.baud_base = baud_base; + req.irq = irq; + req.port = port; + req.flags = 0; + + return register_serial(&req); +} + +static int __devinit serial_card_probe(struct expansion_card *ec, const struct ecard_id *id) +{ + struct serial_card_info *info; + struct serial_card_type *type = id->data; + unsigned long cardaddr, address; + int port; + + ecard_claim (ec); + + info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + memset(info, 0, sizeof(struct serial_card_info)); + info->num_ports = type->num_ports; + + cardaddr = ecard_address(ec, type->type, type->speed); + + for (port = 0; port < info->num_ports; port ++) { + address = cardaddr + type->offset[port]; + + info->ports[port] = -1; + info->base[port] = address; + + if (!request_region(address, 8, "acornserial")) + continue; + + info->ports[port] = serial_register_onedev(address, ec->irq, type->baud_base); + if (info->ports[port] < 0) + break; + } + + return 0; +} + +static void __devexit serial_card_remove(struct expansion_card *ec) +{ + struct serial_card_info *info = ecard_get_drvdata(ec); + int i; + + ecard_set_drvdata(ec, NULL); + + for (i = 0; i < info->num_ports; i++) { + if (info->ports[i] > 0) { + unregister_serial(info->ports[i]); + release_region(info->base[i], 8); + } + } + + kfree(info); + + ecard_release(ec); +} + +static struct serial_card_type atomwide_type = { + .num_ports = 3, + .baud_base = 7372800 / 16, + .type = ECARD_IOC, + .speed = ECARD_SLOW, + .offset = { 0xa00, 0x900, 0x800 }, +}; + +static struct serial_card_type serport_type = { + .num_ports = 2, + .baud_base = 3686400 / 16, + .type = ECARD_IOC, + .speed = ECARD_SLOW, + .offset = { 0x800, 0x808 }, +}; + +static const struct ecard_id serial_cids[] = { + { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL, &atomwide_type }, + { MANU_SERPORT, PROD_SERPORT_DSPORT, &serport_type }, + { 0xffff, 0xffff } +}; + +static struct ecard_driver serial_card_driver = { + .probe = serial_card_probe, + .remove = __devexit_p(serial_card_remove), + .id_table = serial_cids, + .drv = { + .name = "acornserial", + }, +}; + +static int __init serial_card_init(void) +{ + return ecard_register_driver(&serial_card_driver); +} + +static void __exit serial_card_exit(void) +{ + ecard_remove_driver(&serial_card_driver); +} + +MODULE_AUTHOR("Russell King"); +MODULE_LICENSE("GPL"); + +module_init(serial_card_init); +module_exit(serial_card_exit); diff -Nru a/drivers/serial/Config.help b/drivers/serial/Config.help --- a/drivers/serial/Config.help Tue Oct 15 20:29:13 2002 +++ b/drivers/serial/Config.help Tue Oct 15 20:29:13 2002 @@ -103,20 +103,15 @@ CONFIG_SERIAL_8250_RSA ::: To be written ::: -CONFIG_ATOMWIDE_SERIAL - If you have an Atomwide Serial card for an Acorn system, say Y to - this option. The driver can handle 1, 2, or 3 port cards. - If unsure, say N. - -CONFIG_DUALSP_SERIAL - If you have the Serial Port's dual serial card for an Acorn system, - say Y to this option. If unsure, say N. +CONFIG_SERIAL_8250_ACORN + If you have an Atomwide Serial card or Serial Port card for an Acorn + system, say Y to this option. The driver can handle 1, 2, or 3 port + cards. If unsure, say N. CONFIG_SERIAL_ANAKIN ::: To be written ::: -CONFIG_SERIAL_ANAKIN_CONSOLE - ::: To be written ::: +CONFIG_SERIAL_ANAKIN_CONSOLE Even if you say Y here, the currently visible virtual console (/dev/tty0) will still be used as the system console by default, but you can alter that using a kernel command line option such as @@ -149,8 +144,6 @@ ::: To be written ::: CONFIG_SERIAL_CLPS711X_CONSOLE - ::: To be written ::: - Even if you say Y here, the currently visible virtual console (/dev/tty0) will still be used as the system console by default, but you can alter that using a kernel command line option such as diff -Nru a/drivers/serial/Config.in b/drivers/serial/Config.in --- a/drivers/serial/Config.in Tue Oct 15 20:29:12 2002 +++ b/drivers/serial/Config.in Tue Oct 15 20:29:12 2002 @@ -22,8 +22,7 @@ comment 'Non-8250 serial port support' if [ "$CONFIG_ARM" = "y" ]; then - dep_tristate 'Acorn Atomwide 16550 serial port support' CONFIG_ATOMWIDE_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 - dep_tristate 'Acorn Dual 16550 serial port support' CONFIG_DUALSP_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 + dep_tristate 'Acorn expansion card serial port support' CONFIG_SERIAL_8250_ACORN $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 dep_bool 'Anakin serial port support' CONFIG_SERIAL_ANAKIN $CONFIG_ARCH_ANAKIN dep_bool ' Console on Anakin serial port' CONFIG_SERIAL_ANAKIN_CONSOLE $CONFIG_SERIAL_ANAKIN if [ "$CONFIG_SERIAL_ANAKIN" = "y" ]; then @@ -53,7 +52,6 @@ if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then define_bool CONFIG_SERIAL_SUNCORE y - define_bool CONFIG_SERIAL_CORE_CONSOLE y tristate 'Sun Zilog8530 serial support' CONFIG_SERIAL_SUNZILOG dep_tristate 'Sun SU serial support' CONFIG_SERIAL_SUNSU $CONFIG_PCI dep_tristate 'Sun Siemens SAB82532 serial support' CONFIG_SERIAL_SUNSAB $CONFIG_PCI @@ -63,16 +61,14 @@ "$CONFIG_SERIAL_21285" = "y" -o "$CONFIG_SERIAL_SA1100" = "y" -o \ "$CONFIG_SERIAL_ANAKIN" = "y" -o "$CONFIG_SERIAL_UART00" = "y" -o \ "$CONFIG_SERIAL_8250" = "y" -o "$CONFIG_SERIAL_ROCKETPORT" = "y" -o \ - "$CONFIG_SERIAL_SUNZILOG" = "y" -o "$CONFIG_SERIAL_SUNSU" = "y" -o \ - "$CONFIG_SERIAL_SUNSAB" = "y" ]; then + "$CONFIG_SERIAL_SUNCORE" = "y" ]; then define_bool CONFIG_SERIAL_CORE y else if [ "$CONFIG_SERIAL_AMBA" = "m" -o "$CONFIG_SERIAL_CLPS711X" = "m" -o \ "$CONFIG_SERIAL_21285" = "m" -o "$CONFIG_SERIAL_SA1100" = "m" -o \ "$CONFIG_SERIAL_ANAKIN" = "m" -o "$CONFIG_SERIAL_UART00" = "m" -o \ "$CONFIG_SERIAL_8250" = "m" -o "$CONFIG_SERIAL_ROCKETPORT" = "m" -o \ - "$CONFIG_SERIAL_SUNZILOG" = "m" -o "$CONFIG_SERIAL_SUNSU" = "m" -o \ - "$CONFIG_SERIAL_SUNSAB" = "m" ]; then + "$CONFIG_SERIAL_SUNCORE" = "m" ]; then define_bool CONFIG_SERIAL_CORE m fi fi diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile Tue Oct 15 20:29:17 2002 +++ b/drivers/serial/Makefile Tue Oct 15 20:29:17 2002 @@ -13,6 +13,7 @@ obj-$(CONFIG_SERIAL_21285) += 21285.o obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y) obj-$(CONFIG_SERIAL_8250_CS) += 8250_cs.o +obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o obj-$(CONFIG_SERIAL_AMBA) += amba.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c --- a/drivers/serial/core.c Tue Oct 15 20:29:14 2002 +++ b/drivers/serial/core.c Tue Oct 15 20:29:14 2002 @@ -593,7 +593,7 @@ tmp.line = port->line; tmp.port = port->iobase; if (HIGH_BITS_OFFSET) - tmp.port_high = port->iobase >> HIGH_BITS_OFFSET; + tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET; tmp.irq = port->irq; tmp.flags = port->flags | info->flags; tmp.xmit_fifo_size = port->fifosize; diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c --- a/drivers/tc/zs.c Tue Oct 15 20:29:20 2002 +++ b/drivers/tc/zs.c Tue Oct 15 20:29:20 2002 @@ -443,7 +443,7 @@ if (break_pressed && info->line == sercons.index) { if (ch != 0 && time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL, NULL); + handle_sysrq(ch, regs, NULL); break_pressed = 0; goto ignore_char; } diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c --- a/drivers/usb/core/hcd-pci.c Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/core/hcd-pci.c Tue Oct 15 20:29:17 2002 @@ -62,6 +62,9 @@ int retval, region; char buf [8], *bufp = buf; + if (usb_disabled()) + return -ENODEV; + if (!id || !(driver = (struct hc_driver *) id->driver_data)) return -EINVAL; diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/core/hub.c Tue Oct 15 20:29:16 2002 @@ -943,7 +943,9 @@ list_del_init(tmp); - down(&hub->khubd_sem); /* never blocks, we were on list */ + if (unlikely(down_trylock(&hub->khubd_sem))) + BUG(); /* never blocks, we were on list */ + spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { @@ -1067,10 +1069,10 @@ } static struct usb_device_id hub_id_table [] = { - { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS, - bDeviceClass: USB_CLASS_HUB}, - { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS, - bInterfaceClass: USB_CLASS_HUB}, + { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, + .bDeviceClass = USB_CLASS_HUB}, + { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, + .bInterfaceClass = USB_CLASS_HUB}, { } /* Terminating entry */ }; diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c --- a/drivers/usb/core/inode.c Tue Oct 15 20:29:12 2002 +++ b/drivers/usb/core/inode.c Tue Oct 15 20:29:12 2002 @@ -45,7 +45,8 @@ static struct vfsmount *usbdevfs_mount; static struct vfsmount *usbfs_mount; static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; -static int mount_count; /* = 0 */ +static int usbdevfs_mount_count; /* = 0 */ +static int usbfs_mount_count; /* = 0 */ static struct dentry *devices_usbdevfs_dentry; static struct dentry *devices_usbfs_dentry; @@ -507,14 +508,14 @@ }; /* --------------------------------------------------------------------- */ -static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount) +static int get_mount (struct file_system_type *fs_type, struct vfsmount **mount, int *mount_count) { struct vfsmount *mnt; spin_lock (&mount_lock); if (*mount) { mntget(*mount); - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); goto go_ahead; } @@ -528,33 +529,33 @@ spin_lock (&mount_lock); if (!*mount) { *mount = mnt; - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); goto go_ahead; } mntget(*mount); - ++mount_count; + ++(*mount_count); spin_unlock (&mount_lock); mntput(mnt); go_ahead: - dbg("mount_count = %d", mount_count); + dbg("mount_count = %d", *mount_count); return 0; } -static void put_mount (struct vfsmount **mount) +static void put_mount (struct vfsmount **mount, int *mount_count) { struct vfsmount *mnt; spin_lock (&mount_lock); mnt = *mount; - --mount_count; - if (!mount_count) + --(*mount_count); + if (!(*mount_count)) *mount = NULL; spin_unlock (&mount_lock); mntput(mnt); - dbg("mount_count = %d", mount_count); + dbg("mount_count = %d", *mount_count); } static int create_special_files (void) @@ -563,13 +564,13 @@ int retval = 0; /* create the devices special file */ - retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount); + retval = get_mount (&usbdevice_fs_type, &usbdevfs_mount, &usbdevfs_mount_count); if (retval) { err ("Unable to get usbdevfs mount"); goto exit; } - retval = get_mount (&usb_fs_type, &usbfs_mount); + retval = get_mount (&usb_fs_type, &usbfs_mount, &usbfs_mount_count); if (retval) { err ("Unable to get usbfs mount"); goto error_clean_usbdevfs_mount; @@ -604,10 +605,10 @@ devices_usbfs_dentry = NULL; error_clean_mounts: - put_mount (&usbfs_mount); + put_mount (&usbfs_mount, &usbfs_mount_count); error_clean_usbdevfs_mount: - put_mount (&usbdevfs_mount); + put_mount (&usbdevfs_mount, &usbdevfs_mount_count); exit: return retval; @@ -621,8 +622,8 @@ fs_remove_file (devices_usbfs_dentry); devices_usbdevfs_dentry = NULL; devices_usbfs_dentry = NULL; - put_mount (&usbdevfs_mount); - put_mount (&usbfs_mount); + put_mount (&usbdevfs_mount, &usbdevfs_mount_count); + put_mount (&usbfs_mount, &usbfs_mount_count); } void usbfs_update_special (void) diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Tue Oct 15 20:29:14 2002 +++ b/drivers/usb/core/message.c Tue Oct 15 20:29:14 2002 @@ -756,6 +756,7 @@ * * This is used to enable data transfers on interfaces that may not * be enabled by default. Not all devices support such configurability. + * Only the driver bound to an interface may change its setting. * * Within any given configuration, each interface may have several * alternative settings. These are often used to control levels of @@ -808,6 +809,22 @@ interface, NULL, 0, HZ * 5)) < 0) return ret; + /* FIXME drivers shouldn't need to replicate/bugfix the logic here + * when they implement async or easily-killable versions of this or + * other "should-be-internal" functions (like clear_halt). + * should hcd+usbcore postprocess control requests? + */ + + /* prevent submissions using previous endpoint settings */ + iface_as = iface->altsetting + iface->act_altsetting; + for (i = 0; i < iface_as->bNumEndpoints; i++) { + u8 ep = iface_as->endpoint [i].bEndpointAddress; + int out = !(ep & USB_DIR_IN); + + ep &= USB_ENDPOINT_NUMBER_MASK; + (out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0; + // FIXME want hcd hook here, "no such endpoint" + } iface->act_altsetting = alternate; /* 9.1.1.5: reset toggles for all endpoints affected by this iface-as @@ -819,21 +836,20 @@ * any SetInterface request and hence assume toggles need to be reset. * However, EP0 toggles are re-synced for every individual transfer * during the SETUP stage - hence EP0 toggles are "don't care" here. + * (Likewise, EP0 never "halts" on well designed devices.) */ iface_as = &iface->altsetting[alternate]; for (i = 0; i < iface_as->bNumEndpoints; i++) { u8 ep = iface_as->endpoint[i].bEndpointAddress; + int out = !(ep & USB_DIR_IN); - usb_settoggle(dev, ep&USB_ENDPOINT_NUMBER_MASK, usb_endpoint_out(ep), 0); + ep &= USB_ENDPOINT_NUMBER_MASK; + usb_settoggle (dev, ep, out, 0); + (out ? dev->epmaxpacketout : dev->epmaxpacketin) [ep] + = iface_as->endpoint [ep].wMaxPacketSize; } - /* usb_set_maxpacket() sets the maxpacket size for all EP in all - * interfaces but it shouldn't do any harm here: we have changed - * the AS for the requested interface only, hence for unaffected - * interfaces it's just re-application of still-valid values. - */ - usb_set_maxpacket(dev); return 0; } diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c --- a/drivers/usb/core/urb.c Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/core/urb.c Tue Oct 15 20:29:17 2002 @@ -272,9 +272,9 @@ /* enforce simple/standard policy */ allowed = USB_ASYNC_UNLINK; // affects later unlinks allowed |= URB_NO_DMA_MAP; + allowed |= URB_NO_INTERRUPT; switch (temp) { case PIPE_BULK: - allowed |= URB_NO_INTERRUPT; if (is_out) allowed |= USB_ZERO_PACKET; /* FALLTHROUGH */ diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/core/usb.c Tue Oct 15 20:29:17 2002 @@ -50,6 +50,9 @@ extern void usb_major_cleanup(void); +int nousb; /* Disable USB when built into kernel image */ + /* Not honored on modular build */ + static int generic_probe (struct device *dev) { @@ -167,6 +170,9 @@ { int retval = 0; + if (nousb) + return -ENODEV; + new_driver->driver.name = (char *)new_driver->name; new_driver->driver.bus = &usb_bus_type; new_driver->driver.probe = usb_device_probe; @@ -1338,11 +1344,37 @@ .hotplug = usb_hotplug, }; +#ifndef MODULE + +static int __init usb_setup_disable(char *str) +{ + nousb = 1; + return 1; +} + +/* format to disable USB on kernel command line is: nousb */ +__setup("nousb", usb_setup_disable); + +#endif + +/* + * for external read access to + */ +int usb_disabled(void) +{ + return nousb; +} + /* * Init */ static int __init usb_init(void) { + if (nousb) { + info("USB support disabled\n"); + return 0; + } + bus_register(&usb_bus_type); usb_major_init(); usbfs_init(); @@ -1358,6 +1390,10 @@ */ static void __exit usb_exit(void) { + /* This will matter if shutdown/reboot does exitcalls. */ + if (nousb) + return; + remove_driver(&usb_generic_driver); usb_major_cleanup(); usbfs_cleanup(); @@ -1377,6 +1413,7 @@ EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); +EXPORT_SYMBOL(usb_disabled); EXPORT_SYMBOL(usb_device_probe); EXPORT_SYMBOL(usb_device_remove); diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c --- a/drivers/usb/host/ehci-hcd.c Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/host/ehci-hcd.c Tue Oct 15 20:29:17 2002 @@ -985,6 +985,9 @@ static int __init init (void) { dbg (DRIVER_INFO); + if (usb_disabled()) + return -ENODEV; + dbg ("block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd", sizeof (struct ehci_qh), sizeof (struct ehci_qtd), sizeof (struct ehci_itd), sizeof (struct ehci_sitd)); diff -Nru a/drivers/usb/host/hc_sl811.c b/drivers/usb/host/hc_sl811.c --- a/drivers/usb/host/hc_sl811.c Tue Oct 15 20:29:19 2002 +++ b/drivers/usb/host/hc_sl811.c Tue Oct 15 20:29:19 2002 @@ -1321,6 +1321,9 @@ int ret; DBGFUNC ("Enter hci_hcd_init\n"); + if (usb_disabled()) + return -ENODEV; + ret = hc_found_hci (base_addr, data_reg_addr, irq); return ret; diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c --- a/drivers/usb/host/ohci-pci.c Tue Oct 15 20:29:19 2002 +++ b/drivers/usb/host/ohci-pci.c Tue Oct 15 20:29:19 2002 @@ -365,6 +365,9 @@ static int __init ohci_hcd_pci_init (void) { dbg (DRIVER_INFO " (PCI)"); + if (usb_disabled()) + return -ENODEV; + dbg ("block sizes: ed %d td %d", sizeof (struct ed), sizeof (struct td)); return pci_module_init (&ohci_pci_driver); diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c --- a/drivers/usb/host/ohci-sa1111.c Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/host/ohci-sa1111.c Tue Oct 15 20:29:17 2002 @@ -23,6 +23,8 @@ #error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined." #endif +extern int usb_disabled(void); + /*-------------------------------------------------------------------------*/ static void sa1111_start_hc(struct sa1111_dev *dev) @@ -354,6 +356,9 @@ struct sa1111_dev *dev = SA1111_DEV(_dev); struct usb_hcd *hcd = NULL; int ret; + + if (usb_disabled()) + return -ENODEV; ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &hcd, dev); diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c Tue Oct 15 20:29:21 2002 +++ b/drivers/usb/host/uhci-hcd.c Tue Oct 15 20:29:21 2002 @@ -2484,6 +2484,9 @@ info(DRIVER_DESC " " DRIVER_VERSION); + if (usb_disabled()) + return -ENODEV; + if (debug) { errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); if (!errbuf) diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Tue Oct 15 20:29:12 2002 +++ b/drivers/usb/input/wacom.c Tue Oct 15 20:29:12 2002 @@ -402,7 +402,6 @@ struct usb_device *dev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; struct wacom *wacom; - char rep_data[2] = {0x02, 0x02}; char path[64]; if (!(wacom = kmalloc(sizeof(struct wacom), GFP_KERNEL))) diff -Nru a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile --- a/drivers/usb/media/Makefile Tue Oct 15 20:29:11 2002 +++ b/drivers/usb/media/Makefile Tue Oct 15 20:29:11 2002 @@ -14,6 +14,6 @@ obj-$(CONFIG_USB_PWC) += pwc.o obj-$(CONFIG_USB_SE401) += se401.o obj-$(CONFIG_USB_STV680) += stv680.o -obj-$(CONFIG_USB_VICAM) += vicam.o +obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o include $(TOPDIR)/Rules.make diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c --- a/drivers/usb/media/vicam.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/media/vicam.c Tue Oct 15 20:29:16 2002 @@ -1,102 +1,356 @@ -/* -*- linux-c -*- - * USB ViCAM driver - * - * Copyright (c) 2001 Christopher L Cheney (ccheney@cheney.cx) - * Copyright (c) 2001 Pavel Machek (pavel@suse.cz) sponsored by SuSE - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the 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 driver is for the Vista Imaging ViCAM and 3Com HomeConnect USB - * - * Thanks to Greg Kroah-Hartman for the USB Skeleton driver - * - * TODO: - * - find out the ids for the Vista Imaging ViCAM +/* + * USB ViCam WebCam driver + * Copyright (c) 2002 Joe Burks (jburks@wavicle.org) * - * History: + * Supports 3COM HomeConnect PC Digital WebCam * - * 2001_07_07 - 0.1 - christopher: first version - * 2001_08_28 - 0.2 - pavel: messed it up, but for some fun, try - while true; do dd if=/dev/video of=/dev/fb0 bs=$[0x1e480] count=1 2> /dev/null; done - yep, moving pictures. - * 2001_08_29 - 0.3 - pavel: played a little bit more. Experimental mmap support. For some fun, - get gqcam-0.9, compile it and run. Better than dd ;-). - * 2001_08_29 - 0.4 - pavel: added shutter speed control (not much functional) - kill update_params if it does not seem to work for you. - * 2001_08_30 - 0.5 - pavel: fixed stupid bug with update_params & vicam_bulk + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This source code is based heavily on the CPiA webcam driver which was + * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt + * + * Portions of this code were also copied from usbvideo.c + * + * Special thanks to the the whole team at Sourceforge for help making + * this driver become a reality. Notably: + * Andy Armstrong who reverse engineered the color encoding and + * Pavel Machek and Chris Cheney who worked on reverse engineering the + * camera controls and wrote the first generation driver. + * */ - * - * FIXME: It crashes on rmmod with camera plugged. - */ -#define DEBUG 1 - -#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 "usbvideo.h" -#include +// #define VICAM_DEBUG -#include "vicam.h" -#include "vicamurbs.h" +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(a) +#endif + +#ifndef bool +#define bool int +#endif + +#ifdef VICAM_DEBUG +#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args) +#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args) +#else +#define DBG(fmn,args...) do {} while(0) +#endif /* Version Information */ -#define DRIVER_VERSION "v0" -#define DRIVER_AUTHOR "Christopher L Cheney , Pavel Machek " -#define DRIVER_DESC "USB ViCAM Driver" +#define DRIVER_VERSION "v1.0" +#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" +#define DRIVER_DESC "ViCam WebCam Driver" /* Define these values to match your device */ -#define USB_VICAM_VENDOR_ID 0x04C1 -#define USB_VICAM_PRODUCT_ID 0x009D +#define USB_VICAM_VENDOR_ID 0x04c1 +#define USB_VICAM_PRODUCT_ID 0x009d -/* table of devices that work with this driver */ -static struct usb_device_id vicam_table [] = { - { USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID) }, - { } /* Terminating entry */ -}; +#define VICAM_BYTES_PER_PIXEL 3 +#define VICAM_MAX_READ_SIZE (512*242+128) +#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) +#define VICAM_FRAMES 2 + +/* Not sure what all the bytes in these char + * arrays do, but they're necessary to make + * the camera work. + */ -MODULE_DEVICE_TABLE (usb, vicam_table); +static unsigned char setup1[] = { + 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, 0xE7, 0x67, + 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, 0xDE, 0x00, + 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, 0xC0, 0x17, + 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, 0x00, 0x00, + 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 +}; -static int video_nr = -1; /* next avail video device */ -static struct usb_driver vicam_driver; +static unsigned char setup2[] = { + 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, 0x18, 0x00, + 0x00, 0x00 +}; -static char *buf, *buf2; -static volatile int change_pending = 0; +static unsigned char setup3[] = { + 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, 0x00, 0x00 +}; -static int vicam_parameters(struct usb_vicam *vicam); +static unsigned char setup4[] = { + 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, 0xE7, 0x07, + 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, 0x00, 0x00, + 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, 0xAA, 0x00, + 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, 0xE7, 0x07, + 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, 0x7C, 0x00, + 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, 0x18, 0x00, + 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, 0xE7, 0x07, + 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, + 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, 0x24, 0xC0, + 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, 0xE7, 0x07, + 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, 0x01, 0x00, + 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, 0x00, 0xC0, + 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, 0x09, 0xC1, + 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, 0xE7, 0x09, + 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, + 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, 0xC0, 0xDF, + 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, 0x17, 0x02, + 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, + 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, 0xFF, 0xFF, + 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, 0x00, 0x00, + 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, 0xC6, 0x00, + 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, 0xC1, 0x05, + 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, 0x27, 0xDA, + 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x0B, 0x06, + 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, 0x9F, 0xAF, + 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, 0xFC, 0x05, + 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, 0x26, 0x01, + 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x09, + 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, 0x02, 0x06, + 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, 0xFC, 0x05, + 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, 0x27, 0xDA, + 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, 0xFA, 0x05, + 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, + 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, 0x40, 0x00, + 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, 0x9F, 0xAF, + 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, 0x02, 0x00, + 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, 0x9F, 0xA0, + 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, 0x09, 0x06, + 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, 0x01, 0x00, + 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, 0xE7, 0x07, + 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, 0x47, 0xAF, + 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, 0x2E, 0x00, + 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, + 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, 0xC0, 0x57, + 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, 0xC0, 0x57, + 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, 0x55, 0x00, + 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, 0x9F, 0xC0, + 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, 0xC1, 0x0B, + 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, 0x08, 0x06, + 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, + 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, 0x2F, 0x0E, + 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, + 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, + 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, 0x02, 0x00, + 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, 0x09, 0x06, + 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, 0x7F, 0xFF, + 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, 0x22, 0xC0, + 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, + 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, 0xB8, 0x05, + 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, 0x9F, 0xAF, + 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, 0x24, 0xC0, + 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, 0xC8, 0x07, + 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xC1, 0x07, + 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0x9F, 0xAF, + 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, 0x9F, 0xAF, + 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, + 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, 0x0F, 0xC1, + 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x67, + 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x08, 0x00, + 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, 0xEF, 0x07, + 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, 0xEF, 0x07, + 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, 0xEF, 0x07, + 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, 0x00, 0x00, + 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, 0x09, 0x06, + 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xE7, 0x67, + 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, 0x17, 0xD8, + 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, + 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, 0x97, 0xCF, + 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, 0xDA, 0x02, + 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, + 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0x0E, 0x06, + 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, 0xF8, 0x05, + 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, + 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, 0x02, 0x00, + 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, 0x06, 0x06, + 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, 0xE7, 0x07, + 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, 0xE2, 0x05, + 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, 0xF8, 0x05, + 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, 0x00, 0x80, + 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, 0x66, 0x04, + 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, 0x97, 0xCF, + 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, 0x0C, 0x06, + 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0x68, 0x00, + 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, 0x44, 0x05, + 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, 0xE0, 0x07, + 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, 0xE8, 0x07, + 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, 0xE0, 0x07, + 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, 0x97, 0xCF, + 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, 0xEF, 0x07, + 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, 0x0E, 0x06, + 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, 0xFE, 0x05, + 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, 0xE7, 0x07, + 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, 0x07, 0x00, + 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, 0x02, 0x00, + 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, 0xEF, 0x77, + 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, 0x14, 0x04, + 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, 0x37, 0xC0, + 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, 0x0F, 0xC1, + 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, 0xC0, 0x07, + 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, + 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, + 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, + 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x77, + 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, 0x75, 0xC1, + 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, 0xC0, 0x07, + 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, 0x06, 0x06, + 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, + 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, + 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, 0xEF, 0x07, + 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, 0x01, 0x00, + 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, 0x01, 0x00, + 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, 0xFF, 0x4F, + 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, 0x38, 0x00, + 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, 0x03, 0x00, + 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, 0x08, 0xDA, + 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, + 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, 0x06, 0x06, + 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, 0xC1, 0x0B, + 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x09, + 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, 0xFA, 0x05, + 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, 0xE7, 0x07, + 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, 0x40, 0x00, + 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, 0x9F, 0xAF, + 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, 0xE2, 0x05, + 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, 0x23, 0x00, + 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, 0x04, 0x00, + 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, 0xE6, 0x05, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x07, 0x00, + 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, 0x9F, 0xAF, + 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, 0xC1, 0x09, + 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, + 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, 0xC1, 0xD1, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0D, 0x00, + 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, 0x32, 0x00, + 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0F, 0x00, + 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, 0x28, 0x05, + 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, 0x24, 0xC0, + 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, 0xC0, 0x67, + 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, 0xE7, 0x87, + 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xF9, + 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, 0x72, 0xC1, + 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, 0x97, 0xCF, + 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, 0xFF, 0x00, + 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, 0x24, 0xC0, + 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0xE7, 0x87, + 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, + 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, 0xE7, 0x67, + 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, + 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, 0xE7, 0x67, + 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, + 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x00, 0x01, + 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, 0x40, 0x00, + 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, 0x00, 0xFF, + 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, 0x24, 0xC0, + 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x67, + 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, 0xE8, 0x09, + 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, + 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, 0x00, 0xDA, + 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, 0xE7, 0x87, + 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xE7, 0x07, + 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, + 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0xE7, 0x07, + 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, 0x00, 0x80, + 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, 0x09, 0x02, + 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, + 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; -/****************************************************************************** - * - * Memory management functions - * - * Taken from bttv-drivers.c 2.4.7-pre3 - * - ******************************************************************************/ +static unsigned char setup5[] = { + 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, 0x0E, 0x00, + 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, 0x26, 0x00, + 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, 0x92, 0x00, + 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, 0xB8, 0x00, + 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, 0xCE, 0x00, + 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, 0xE0, 0x00, + 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, 0xEC, 0x00, + 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, 0x0A, 0x01, + 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, 0x22, 0x01, + 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, 0x36, 0x01, + 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, 0x72, 0x01, + 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, 0x88, 0x01, + 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, 0xA0, 0x01, + 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, 0xB4, 0x01, + 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, 0xF6, 0x01, + 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, 0x3C, 0x02, + 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, 0x56, 0x02, + 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, 0x84, 0x02, + 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, 0x8E, 0x02, + 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, 0xAE, 0x02, + 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, 0xC0, 0x02, + 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, 0xD4, 0x02, + 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, 0xF8, 0x02, + 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, 0x24, 0x03, + 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, 0x3C, 0x03, + 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, 0x58, 0x03, + 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, 0x7A, 0x03, + 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, 0xB2, 0x03, + 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, 0xD4, 0x03, + 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, 0xFC, 0x03, + 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, 0x32, 0x04, + 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, 0x42, 0x04, + 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, 0x54, 0x04, + 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, 0x62, 0x04, + 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, 0x80, 0x04, + 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, 0x9A, 0x04, + 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, 0xB4, 0x04, + 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, 0x2A, 0x05, + 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 +}; -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the area. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) +static unsigned long kvirt_to_pa(unsigned long adr) { unsigned long kva, ret; @@ -106,526 +360,734 @@ return ret; } -static void * rvmalloc(unsigned long size) +/* rvmalloc / rvfree copied from usbvideo.c + * + * Not sure why these are not yet non-statics which I can reference through + * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime + * in the future. + * +*/ +static void *rvmalloc(unsigned long size) { - void * mem; + void *mem; unsigned long adr; - size=PAGE_ALIGN(size); - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - mem_map_reserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } + size = PAGE_ALIGN(size); + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + while (size > 0) { + mem_map_reserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; } + return mem; } -static void rvfree(void * mem, unsigned long size) +static void rvfree(void *mem, unsigned long size) { unsigned long adr; - if (mem) - { - adr=(unsigned long) mem; - while ((long) size > 0) - { - mem_map_unreserve(vmalloc_to_page((void *)adr)); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); + if (!mem) + return; + + adr = (unsigned long) mem; + while ((long) size > 0) { + mem_map_unreserve(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; } + vfree(mem); } + +struct vicam_camera { + u16 shutter_speed; // capture shutter speed + u16 gain; // capture gain -/****************************************************************************** - * - * Foo Bar - * - ******************************************************************************/ + u8 *raw_image; // raw data captured from the camera + u8 *framebuf; // processed data in RGB24 format -/** - * usb_vicam_debug_data - */ -static inline void usb_vicam_debug_data (const char *function, int size, const unsigned char *data) -{ - int i; + struct video_device vdev; // v4l video device + struct usb_device *udev; // usb device - if (!debug) - return; + struct semaphore busy_lock; // guard against SMP multithreading - printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", - function, size); - for (i = 0; i < size; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); -} + bool is_initialized; + u8 open_count; + u8 bulkEndpoint; + bool needsDummyRead; -/***************************************************************************** - * - * Send command to vicam - * - *****************************************************************************/ + u32 framebuf_size; // # of valid bytes in framebuf + u32 framebuf_read_start; // position in frame buf that a read is happening at. -static int vicam_sndctrl(int set, struct usb_vicam *vicam, unsigned short req, - unsigned short value, unsigned char *cp, int size) -{ - int ret; - unsigned char *transfer_buffer = kmalloc (size, GFP_KERNEL); +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_entry; +#endif + +}; + +static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); +static void vicam_disconnect(struct usb_interface *intf); +static void read_frame(struct vicam_camera *cam, int framenum); + +static int +send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index, + unsigned char *cp, u16 size) +{ + int status; + + // for reasons not yet known to me, you can't send USB control messages + // with data in the module (if you are compiled as a module). Whatever + // the reason, copying it to memory allocated as kernel memory then + // doing the usb control message fixes the problem. - /* Needs to return data I think, works for sending though */ + unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); memcpy(transfer_buffer, cp, size); - - ret = usb_control_msg ( vicam->udev, set ? usb_sndctrlpipe(vicam->udev, 0) : usb_rcvctrlpipe(vicam->udev, 0), req, (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, 0, transfer_buffer, size, HZ); + + status = usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + request, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, + transfer_buffer, size, HZ); kfree(transfer_buffer); - if (ret) - printk("vicam: error: %d\n", ret); - mdelay(100); - return ret; -} + if (status < 0) { + printk(KERN_INFO "Failed sending control message, error %d.\n", + status); + } + + return status; +} + +static int +initialize_camera(struct vicam_camera *cam) +{ + struct usb_device *udev = cam->udev; + int status; + + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup1, sizeof (setup1))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup2, sizeof (setup2))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup4, sizeof (setup4))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup5, sizeof (setup5))) < 0) + return status; + if ((status = + send_control_msg(udev, 0xff, 0, 0, setup3, sizeof (setup3))) < 0) + return status; -/***************************************************************************** - * - * Video4Linux Helpers - * - *****************************************************************************/ + return 0; +} -static int vicam_get_capability(struct usb_vicam *vicam, struct video_capability *b) +static int +set_camera_power(struct vicam_camera *cam, int state) { - dbg("vicam_get_capability"); + int status; - strcpy(b->name, vicam->camera_name); - b->type = VID_TYPE_CAPTURE | VID_TYPE_MONOCHROME; - b->channels = 1; - b->audios = 0; + if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0) + return status; - b->maxwidth = vicam->width[vicam->sizes-1]; - b->maxheight = vicam->height[vicam->sizes-1]; - b->minwidth = vicam->width[0]; - b->minheight = vicam->height[0]; + if (state) { + send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0); + } return 0; } - -static int vicam_get_channel(struct usb_vicam *vicam, struct video_channel *v) + +static int +vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsigned long ul_arg) { - dbg("vicam_get_channel"); + void *arg = (void *)ul_arg; + struct vicam_camera *cam = file->private_data; + int retval = 0; - if (v->channel != 0) - return -EINVAL; - - v->flags = 0; - v->tuners = 0; - v->type = VIDEO_TYPE_CAMERA; - strcpy(v->name, "Camera"); + if (!cam) + return -ENODEV; - return 0; -} - -static int vicam_set_channel(struct usb_vicam *vicam, struct video_channel *v) -{ - dbg("vicam_set_channel"); + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; - if (v->channel != 0) - return -EINVAL; - - return 0; -} - -static int vicam_get_mmapbuffer(struct usb_vicam *vicam, struct video_mbuf *vm) -{ - int i; + switch (ioctlnr) { + /* query capabilites */ + case VIDIOCGCAP: + { + struct video_capability b; - dbg("vicam_get_mmapbuffer"); + DBG("VIDIOCGCAP\n"); + strcpy(b.name, "ViCam-based Camera"); + b.type = VID_TYPE_CAPTURE; + b.channels = 1; + b.audios = 0; + b.maxwidth = 320; /* VIDEOSIZE_CIF */ + b.maxheight = 240; + b.minwidth = 320; /* VIDEOSIZE_48_48 */ + b.minheight = 240; - memset(vm, 0, sizeof(vm)); - vm->size = VICAM_NUMFRAMES * vicam->maxframesize; - vm->frames = VICAM_NUMFRAMES; + if (copy_to_user(arg, &b, sizeof (b))) + retval = -EFAULT; - for (i=0; ioffsets[i] = vicam->maxframesize * i; + break; + } + /* get/set video source - we are a camera and nothing else */ + case VIDIOCGCHAN: + { + struct video_channel v; - return 0; -} + DBG("VIDIOCGCHAN\n"); + if (copy_from_user(&v, arg, sizeof (v))) { + retval = -EFAULT; + break; + } + if (v.channel != 0) { + retval = -EINVAL; + break; + } + + v.channel = 0; + strcpy(v.name, "Camera"); + v.tuners = 0; + v.flags = 0; + v.type = VIDEO_TYPE_CAMERA; + v.norm = 0; + + if (copy_to_user(arg, &v, sizeof (v))) + retval = -EFAULT; + break; + } -static int vicam_get_picture(struct usb_vicam *vicam, struct video_picture *p) -{ - dbg("vicam_get_picture"); + case VIDIOCSCHAN: + { + int v; - /* This is probably where that weird 0x56 call goes */ - p->brightness = vicam->win.brightness; - p->hue = vicam->win.hue; - p->colour = vicam->win.colour; - p->contrast = vicam->win.contrast; - p->whiteness = vicam->win.whiteness; - p->depth = vicam->win.depth; - p->palette = vicam->win.palette; + if (copy_from_user(&v, arg, sizeof (v))) + retval = -EFAULT; + DBG("VIDIOCSCHAN %d\n", v); - return 0; -} + if (retval == 0 && v != 0) + retval = -EINVAL; -static void synchronize(struct usb_vicam *vicam) -{ - DECLARE_WAITQUEUE(wait, current); - change_pending = 1; - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&vicam->wait, &wait); - if (change_pending) - schedule(); - remove_wait_queue(&vicam->wait, &wait); - set_current_state(TASK_RUNNING); - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); - mdelay(10); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); - mdelay(10); -} - -static void params_changed(struct usb_vicam *vicam) -{ -#if 1 - synchronize(vicam); - mdelay(10); - vicam_parameters(vicam); - printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL)); -#endif -} + break; + } -static int vicam_set_picture(struct usb_vicam *vicam, struct video_picture *p) -{ - int changed = 0; - info("vicam_set_picture (%d)", p->brightness); + /* image properties */ + case VIDIOCGPICT: + { + struct video_picture vp; + DBG("VIDIOCGPICT\n"); + memset(&vp, 0, sizeof (struct video_picture)); + vp.brightness = cam->gain << 8; + vp.depth = 24; + vp.palette = VIDEO_PALETTE_RGB24; + if (copy_to_user + (arg, &vp, sizeof (struct video_picture))) + retval = -EFAULT; + break; + } + case VIDIOCSPICT: + { + struct video_picture *vp = (struct video_picture *) arg; -#define SET(x) \ - if (vicam->win.x != p->x) \ - vicam->win.x = p->x, changed = 1; - SET(brightness); - SET(hue); - SET(colour); - SET(contrast); - SET(whiteness); - SET(depth); - SET(palette); - if (changed) - params_changed(vicam); + DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp->depth, + vp->palette); - return 0; - /* Investigate what should be done maybe 0x56 type call */ - if (p->depth != 8) return 1; - if (p->palette != VIDEO_PALETTE_GREY) return 1; + cam->gain = vp->brightness >> 8; - return 0; -} + if (vp->depth != 24 + || vp->palette != VIDEO_PALETTE_RGB24) + retval = -EINVAL; -/* FIXME - vicam_sync_frame - important */ -static int vicam_sync_frame(struct usb_vicam *vicam, int frame) -{ - dbg("vicam_sync_frame"); + break; + } - if(frame <0 || frame >= VICAM_NUMFRAMES) - return -EINVAL; + /* get/set capture window */ + case VIDIOCGWIN: + { + struct video_window vw; + vw.x = 0; + vw.y = 0; + vw.width = 320; + vw.height = 240; + vw.chromakey = 0; + vw.flags = 0; + vw.clips = NULL; + vw.clipcount = 0; + + DBG("VIDIOCGWIN\n"); + + if (copy_to_user + ((void *) arg, (void *) &vw, sizeof (vw))) + retval = -EFAULT; + + // I'm not sure what the deal with a capture window is, it is very poorly described + // in the doc. So I won't support it now. + break; + } - /* Probably need to handle various cases */ -/* ret=vicam_newframe(vicam, frame); - vicam->frame[frame].grabstate=FRAME_UNUSED; -*/ - return 0; -} - -static int vicam_get_window(struct usb_vicam *vicam, struct video_window *vw) -{ - dbg("vicam_get_window"); + case VIDIOCSWIN: + { - vw->x = 0; - vw->y = 0; - vw->chromakey = 0; - vw->flags = 0; - vw->clipcount = 0; - vw->width = vicam->win.width; - vw->height = vicam->win.height; + struct video_window *vw = (struct video_window *) arg; + DBG("VIDIOCSWIN %d x %d\n", vw->width, vw->height); - return 0; -} + if ( vw->width != 320 || vw->height != 240 ) + retval = -EFAULT; + + break; + } -static int vicam_set_window(struct usb_vicam *vicam, struct video_window *vw) -{ - info("vicam_set_window"); - - if (vw->flags) - return -EINVAL; - if (vw->clipcount) - return -EINVAL; + /* mmap interface */ + case VIDIOCGMBUF: + { + struct video_mbuf vm; + int i; - if (vicam->win.width == vw->width && vicam->win.height == vw->height) - return 0; + DBG("VIDIOCGMBUF\n"); + memset(&vm, 0, sizeof (vm)); + vm.size = + VICAM_MAX_FRAME_SIZE * VICAM_FRAMES; + vm.frames = VICAM_FRAMES; + for (i = 0; i < VICAM_FRAMES; i++) + vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i; + + if (copy_to_user + ((void *) arg, (void *) &vm, sizeof (vm))) + retval = -EFAULT; - /* Pick largest mode that is smaller than specified res */ - /* If specified res is too small reject */ + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + // int video_size; - /* Add urb send to device... */ + if (copy_from_user + ((void *) &vm, (void *) arg, sizeof (vm))) { + retval = -EFAULT; + break; + } + + DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format); + + if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 ) + retval = -EINVAL; + + // in theory right here we'd start the image capturing + // (fill in a bulk urb and submit it asynchronously) + // + // Instead we're going to do a total hack job for now and + // retrieve the frame in VIDIOCSYNC - vicam->win.width = vw->width; - vicam->win.height = vw->height; - params_changed(vicam); + break; + } - return 0; + case VIDIOCSYNC: + { + int frame; + + if (copy_from_user((void *) &frame, arg, sizeof (int))) { + retval = -EFAULT; + break; + } + DBG("VIDIOCSYNC: %d\n", frame); + + read_frame(cam, frame); + + break; + } + + /* pointless to implement overlay with this camera */ + case VIDIOCCAPTURE: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case VIDIOCKEY: + retval = -EINVAL; + break; + + /* tuner interface - we have none */ + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + retval = -EINVAL; + break; + + /* audio interface - we have none */ + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + retval = -EINVAL; + break; + default: + retval = -ENOIOCTLCMD; + break; + } + + up(&cam->busy_lock); + return retval; } -/* FIXME - vicam_mmap_capture - important */ -static int vicam_mmap_capture(struct usb_vicam *vicam, struct video_mmap *vm) +static int +vicam_open(struct inode *inode, struct file *file) { - dbg("vicam_mmap_capture"); + struct video_device *dev = video_devdata(file); + struct vicam_camera *cam = + (struct vicam_camera *) dev->priv; + DBG("open\n"); - /* usbvideo.c looks good for using here */ + if (!cam) { + printk(KERN_ERR + "vicam video_device improperly initialized"); + } - /* - if (vm->frame >= VICAM_NUMFRAMES) - return -EINVAL; - if (vicam->frame[vm->frame].grabstate != FRAME_UNUSED) + down_interruptible(&cam->busy_lock); + + if (cam->open_count > 0) { + printk(KERN_INFO + "vicam_open called on already opened camera"); + up(&cam->busy_lock); return -EBUSY; - vicam->frame[vm->frame].grabstate=FRAME_READY; - */ + } - /* No need to vicam_set_window here according to Alan */ + if (!cam->raw_image) { + cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); + if (!cam->raw_image) { + up(&cam->busy_lock); + return -ENOMEM; + } + } - /* - if (!vicam->streaming) - vicam_start_stream(vicam); - */ + if (!cam->framebuf) { + cam->framebuf = + rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); + if (!cam->framebuf) { + kfree(cam->raw_image); + up(&cam->busy_lock); + return -ENOMEM; + } + } + // First upload firmware, then turn the camera on - /* set frame as ready */ + if (!cam->is_initialized) { + initialize_camera(cam); - return 0; -} + cam->is_initialized = 1; + } -/***************************************************************************** - * - * Video4Linux - * - *****************************************************************************/ + set_camera_power(cam, 1); -static int vicam_v4l_open(struct inode *inode, struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct usb_vicam *vicam = (struct usb_vicam *)vdev; - int err = 0; - - dbg("vicam_v4l_open"); - down(&vicam->sem); + cam->needsDummyRead = 1; + cam->open_count++; - vicam->fbuf = rvmalloc(vicam->maxframesize * VICAM_NUMFRAMES); - if (vicam->open_count) { - err = -EBUSY; - } else if (!vicam->fbuf) { - err =- ENOMEM; - } else { -#ifdef BLINKING - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); - info ("led on"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); -#endif - vicam->open_count++; - file->private_data = vdev; - } + up(&cam->busy_lock); - up(&vicam->sem); - return err; + file->private_data = cam; + + return 0; } -static int vicam_v4l_close(struct inode *inode, struct file *file) +static int +vicam_close(struct inode *inode, struct file *file) { - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; - - dbg("vicam_v4l_close"); - - down(&vicam->sem); + struct vicam_camera *cam = file->private_data; + DBG("close\n"); + set_camera_power(cam, 0); -#ifdef BLINKING - info ("led off"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); -// vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); Leave it on -#endif + cam->open_count--; - rvfree(vicam->fbuf, vicam->maxframesize * VICAM_NUMFRAMES); - vicam->fbuf = 0; - vicam->open_count=0; - file->private_data = NULL; - - up(&vicam->sem); - /* Why does se401.c have a usbdevice check here? */ - /* If device is unplugged while open, I guess we only may unregister now */ return 0; } -static int vicam_v4l_read(struct file *file, char *user_buf, - size_t buflen, loff_t *ppos) +inline int pin(int x) { - struct video_device *vdev = file->private_data; - //struct usb_vicam *vicam = (struct usb_vicam *)vdev; + return((x > 255) ? 255 : ((x < 0) ? 0 : x)); +} - dbg("vicam_v4l_read(%d)", buflen); +inline void writepixel(char *rgb, int Y, int Cr, int Cb) +{ + Y = 1160 * (Y - 16); + + rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 ); + rgb[1] = pin( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 ); + rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 ); +} - if (!vdev || !buf) - return -EFAULT; +#define DATA_HEADER_SIZE 64 - if (copy_to_user(user_buf, buf2, buflen)) - return -EFAULT; - return buflen; -} +// -------------------------------------------------------------------------------- +// vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB +// +// Copyright (C) 2002 Monroe Williams (monroe@pobox.com) +// -------------------------------------------------------------------------------- -static int vicam_v4l_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) +void vicam_decode_color( char *data, char *rgb) { - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; - int ret = -EL3RST; + int x,y; + int Cr, Cb; + int sign; + int prevX, nextX, prevY, nextY; + int skip; + unsigned char *src; + unsigned char *dst; - if (!vicam->udev) - return -EIO; + prevY = 512; + nextY = 512; - down(&vicam->sem); + src = data + DATA_HEADER_SIZE; + dst = rgb; - switch (cmd) { - case VIDIOCGCAP: - { - struct video_capability *b = arg; - ret = vicam_get_capability(vicam,b); - dbg("name %s",b->name); - break; - } - case VIDIOCGFBUF: - { - struct video_buffer *vb = arg; - info("vicam_v4l_ioctl - VIDIOCGBUF - query frame buffer param"); - /* frame buffer not supported, not used */ - memset(vb, 0, sizeof(*vb)); - ret = 0; - break; - } - case VIDIOCGWIN: + for(y = 1; y < 241; y += 2) { - struct video_window *vw = arg; - ret = vicam_get_window(vicam, vw); - break; - } - case VIDIOCSWIN: - { - struct video_window *vw = arg; - ret = vicam_set_window(vicam, vw); - break; - } - case VIDIOCGCHAN: - { - struct video_channel *v = arg; + // even line + sign = 1; + prevX = 1; + nextX = 1; - ret = vicam_get_channel(vicam,v); - break; - } - case VIDIOCSCHAN: - { - struct video_channel *v = arg; - ret = vicam_set_channel(vicam,v); - break; - } - case VIDIOCGPICT: - { - struct video_picture *p = arg; - ret = vicam_get_picture(vicam,p); - break; - } - case VIDIOCSPICT: - { - struct video_picture *p = arg; - ret = vicam_set_picture(vicam,p); - break; - } - case VIDIOCGMBUF: - { - struct video_mbuf *vm = arg; - ret = vicam_get_mmapbuffer(vicam,vm); - break; - } - case VIDIOCMCAPTURE: - { - struct video_mmap *vm = arg; - ret = vicam_mmap_capture(vicam,vm); - break; + skip = 0; + + dst = rgb + (y-1)*320*3; + + for(x = 0; x < 512; x++) + { + if(x == 512-1) + nextX = -1; + + Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1; + Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2; + + writepixel( + dst + ((x*5)>>3)*3, + src[0] + (sign * (Cr >> 1)), + Cr, + Cb); + + src++; + sign *= -1; + prevX = -1; + } + + prevY = -512; + + if(y == (242 - 2)) + nextY = -512; + + // odd line + sign = 1; + prevX = 1; + nextX = 1; + + skip = 0; + + dst = rgb + (y)*320*3; + + for(x = 0; x < 512; x++) + { + if(x == 512-1) + nextX = -1; + + Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2; + Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1; + + writepixel( + dst + ((x * 5)>>3)*3, + src[0] - (sign * (Cb >> 1)), + Cr, + Cb); + + src++; + sign *= -1; + prevX = -1; + } } - case VIDIOCSYNC: - { - int *frame = arg; - ret = vicam_sync_frame(vicam,*frame); - break; +} + +static void +read_frame(struct vicam_camera *cam, int framenum) +{ + unsigned char request[16]; + int realShutter; + int n; + int actual_length; + + memset(request, 0, 16); + request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain + + request[1] = 0; // 512x242 capture + + request[2] = 0x90; // the function of these two bytes + request[3] = 0x07; // is not yet understood + + if (cam->shutter_speed > 60) { + // Short exposure + realShutter = + ((-15631900 / cam->shutter_speed) + 260533) / 1000; + request[4] = realShutter & 0xFF; + request[5] = (realShutter >> 8) & 0xFF; + request[6] = 0x03; + request[7] = 0x01; + } else { + // Long exposure + realShutter = 15600 / cam->shutter_speed - 1; + request[4] = 0; + request[5] = 0; + request[6] = realShutter & 0xFF; + request[7] = realShutter >> 8; + } + + // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0 + request[8] = 0; + // bytes 9-15 do not seem to affect exposure or image quality + + n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16); + + if (n < 0) { + printk(KERN_ERR + " Problem sending frame capture control message"); + return; } - case VIDIOCKEY: - ret = 0; - - case VIDIOCCAPTURE: - case VIDIOCSFBUF: - case VIDIOCGTUNER: - case VIDIOCSTUNER: - case VIDIOCGFREQ: - case VIDIOCSFREQ: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOCGUNIT: - ret = -EINVAL; + n = usb_bulk_msg(cam->udev, + usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint), + cam->raw_image, + 512 * 242 + 128, &actual_length, HZ*10); - default: - { - info("vicam_v4l_ioctl - %ui",cmd); - ret = -ENOIOCTLCMD; + if (n < 0) { + printk(KERN_ERR "Problem during bulk read of frame data: %d\n", + n); } - } /* end switch */ - up(&vicam->sem); - return ret; + vicam_decode_color(cam->raw_image, + cam->framebuf + + framenum * VICAM_MAX_FRAME_SIZE ); + + cam->framebuf_size = + 320 * 240 * VICAM_BYTES_PER_PIXEL; + cam->framebuf_read_start = 0; + + return; + } -static int vicam_v4l_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static int +vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos ) { - return video_usercopy(inode, file, cmd, arg, vicam_v4l_do_ioctl); + struct vicam_camera *cam = file->private_data; + DBG("read %d bytes.\n", (int) count); + + if (!buf) + return -EINVAL; + + if (!count) + return -EINVAL; + + // This is some code that will hopefully allow us to do shell copies from + // the /dev/videoX to a file and have it actually work. + if (cam->framebuf_size != 0) { + if (cam->framebuf_read_start == cam->framebuf_size) { + cam->framebuf_size = cam->framebuf_read_start = 0; + return 0; + } else { + if (cam->framebuf_read_start + count <= + cam->framebuf_size) { + // count does not exceed available bytes + copy_to_user(buf, + (cam->framebuf) + + cam->framebuf_read_start, count); + cam->framebuf_read_start += count; + return count; + } else { + count = + cam->framebuf_size - + cam->framebuf_read_start; + copy_to_user(buf, + (cam->framebuf) + + cam->framebuf_read_start, count); + cam->framebuf_read_start = cam->framebuf_size; + return count; + } + } + } + + down_interruptible(&cam->busy_lock); + + if (cam->needsDummyRead) { + read_frame(cam, 0); + cam->needsDummyRead = 0; + } + // read_frame twice because the camera doesn't seem to take the shutter speed for the first one. + + read_frame(cam, 0); + + if (count > cam->framebuf_size) + count = cam->framebuf_size; + + copy_to_user(buf, cam->framebuf, count); + + if (count != cam->framebuf_size) + cam->framebuf_read_start = count; + else + cam->framebuf_size = 0; + + up(&cam->busy_lock); + + return count; } -static int vicam_v4l_mmap(struct file *file, struct vm_area_struct *vma) + +static int +vicam_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_device *vdev = file->private_data; - struct usb_vicam *vicam = (struct usb_vicam *)vdev; + // TODO: allocate the raw frame buffer if necessary + unsigned long page, pos; unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; + struct vicam_camera *cam = file->private_data; - down(&vicam->sem); - - if (vicam->udev == NULL) { - up(&vicam->sem); - return -EIO; - } -#if 0 - if (size > (((VICAM_NUMFRAMES * vicam->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) { - up(&vicam->sem); - return -EINVAL; + if (!cam) + return -ENODEV; + + DBG("vicam_mmap: %ld\n", size); + + /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes + * to the size the application requested for mmap and it was screwing apps up. + if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) + return -EINVAL; + */ + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -EINTR; + + if (!cam->framebuf) { /* we do lazy allocation */ + cam->framebuf = + rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); + if (!cam->framebuf) { + up(&cam->busy_lock); + return -ENOMEM; + } } -#endif - pos = (unsigned long)vicam->fbuf; + + pos = (unsigned long)cam->framebuf; while (size > 0) { page = kvirt_to_pa(pos); - if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&vicam->sem); + if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; - } + start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) @@ -633,299 +1095,315 @@ else size = 0; } - up(&vicam->sem); - return 0; + up(&cam->busy_lock); + + return 0; } -/* FIXME - vicam_template - important */ -static struct file_operations vicam_fops = { - .owner = THIS_MODULE, - .open = vicam_v4l_open, - .release = vicam_v4l_close, - .read = vicam_v4l_read, - .mmap = vicam_v4l_mmap, - .ioctl = vicam_v4l_ioctl, - .llseek = no_llseek, -}; -static struct video_device vicam_template = { - .owner = THIS_MODULE, - .name = "vicam USB camera", - .type = VID_TYPE_CAPTURE, - .hardware = VID_HARDWARE_SE401, /* need to ask for own id */ - .fops = &vicam_fops, -}; +#ifdef CONFIG_PROC_FS -/****************************************************************************** - * - * Some Routines - * - ******************************************************************************/ +static struct proc_dir_entry *vicam_proc_root = NULL; -/* -Flash the led -vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); -info ("led on"); -vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); -info ("led off"); -vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x00, NULL, 0); -vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x00, NULL, 0); -*/ +static int +vicam_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char *out = page; + int len; + struct vicam_camera *cam = (struct vicam_camera *) data; + + out += + sprintf(out, "Vicam-based WebCam Linux Driver.\n"); + out += sprintf(out, "(c) 2002 Joe Burks (jburks@wavicle.org)\n"); + out += sprintf(out, "vicam stats:\n"); + out += sprintf(out, " Shutter Speed: 1/%d\n", cam->shutter_speed); + out += sprintf(out, " Gain: %d\n", cam->gain); + + len = out - page; + len -= off; + if (len < count) { + *eof = 1; + if (len <= 0) + return 0; + } else + len = count; + + *start = page + off; + return len; +} + +static int +vicam_write_proc(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char *in; + char *start; + struct vicam_camera *cam = (struct vicam_camera *) data; + + in = kmalloc(count + 1, GFP_KERNEL); + if (!in) + return -ENOMEM; + + in[count] = 0; // I'm not sure buffer is gauranteed to be null terminated + // so I do this to make sure I have a null in there. + + strncpy(in, buffer, count); + + start = strstr(in, "gain="); + if (start + && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) + cam->gain = simple_strtoul(start + 5, NULL, 10); + + start = strstr(in, "shutter="); + if (start + && (start == in || *(start - 1) == ' ' || *(start - 1) == ',')) + cam->shutter_speed = simple_strtoul(start + 8, NULL, 10); + + kfree(in); + return count; +} -static void vicam_bulk(struct urb *urb) +void +vicam_create_proc_root(void) { - struct usb_vicam *vicam = urb->context; + vicam_proc_root = create_proc_entry("video/vicam", S_IFDIR, 0); - /* if (!vicam || !vicam->dev || !vicam->used) - return; - */ + if (vicam_proc_root) + vicam_proc_root->owner = THIS_MODULE; + else + printk(KERN_ERR + "could not create /proc entry for vicam!"); +} - if (urb->status) - printk("vicam%d: nonzero read/write bulk status received: %d", - 0, urb->status); - - urb->actual_length = 0; - urb->dev = vicam->udev; - - memcpy(buf2, buf+64, 0x1e480); - if (vicam->fbuf) - memcpy(vicam->fbuf, buf+64, 0x1e480); - - if (!change_pending) { - if (usb_submit_urb(urb, GFP_ATOMIC)) - dbg("failed resubmitting read urb"); - } else { - change_pending = 0; - wake_up_interruptible(&vicam->wait); - } +void +vicam_destroy_proc_root(void) +{ + if (vicam_proc_root) + remove_proc_entry("video/vicam", 0); } -static int vicam_parameters(struct usb_vicam *vicam) +void +vicam_create_proc_entry(void *ptr) { - unsigned char req[0x10]; - unsigned int shutter; - shutter = 10; + struct vicam_camera *cam = (struct vicam_camera *) ptr; - switch (vicam->win.width) { - case 512: - default: - memcpy(req, s512x242bw, 0x10); - break; - case 256: - memcpy(req, s256x242bw, 0x10); - break; - case 128: - memcpy(req, s128x122bw, 0x10); - break; + char name[7]; + struct proc_dir_entry *ent; + + DBG(KERN_INFO "vicam: creating proc entry\n"); + + if (!vicam_proc_root || !cam) { + printk(KERN_INFO + "vicam: could not create proc entry, %s pointer is null.\n", + (!cam ? "camera" : "root")); + return; } + sprintf(name, "video%d", cam->vdev.minor); - mdelay(10); - vicam_sndctrl(1, vicam, VICAM_REQ_CAMERA_POWER, 0x01, NULL, 0); - info ("led on"); - vicam_sndctrl(1, vicam, VICAM_REQ_LED_CONTROL, 0x01, NULL, 0); - - mdelay(10); - - shutter = vicam->win.contrast / 256; - if (shutter == 0) - shutter = 1; - printk("vicam_parameters: brightness %d, shutter %d\n", vicam->win.brightness, shutter ); - req[0] = vicam->win.brightness /256; - shutter = 15600/shutter - 1; - req[6] = shutter & 0xff; - req[7] = (shutter >> 8) & 0xff; - vicam_sndctrl(1, vicam, VICAM_REQ_CAPTURE, 0x80, req, 0x10); - mdelay(10); - vicam_sndctrl(0, vicam, VICAM_REQ_GET_SOMETHIN, 0, buf, 0x10); - mdelay(10); + ent = + create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, + vicam_proc_root); + if (!ent) + return; - return 0; + ent->data = cam; + ent->read_proc = vicam_read_proc; + ent->write_proc = vicam_write_proc; + ent->size = 512; + cam->proc_entry = ent; } -static int vicam_init(struct usb_vicam *vicam) +void +vicam_destroy_proc_entry(void *ptr) { - int width[] = {128, 256, 512}; - int height[] = {122, 242, 242}; + struct vicam_camera *cam = (struct vicam_camera *) ptr; + char name[7]; + + if (!cam || !cam->proc_entry) + return; - dbg("vicam_init"); - buf = kmalloc(0x1e480, GFP_KERNEL); - buf2 = kmalloc(0x1e480, GFP_KERNEL); - if ((!buf) || (!buf2)) { - printk("Not enough memory for vicam!\n"); - goto error; - } - - /* do we do aspect correction in kernel or not? */ - vicam->sizes = 3; - vicam->width = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); - vicam->height = kmalloc(vicam->sizes*sizeof(int), GFP_KERNEL); - memcpy(vicam->width, &width, sizeof(width)); - memcpy(vicam->height, &height, sizeof(height)); - vicam->maxframesize = vicam->width[vicam->sizes-1] * vicam->height[vicam->sizes-1]; - - /* Download firmware to camera */ - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware1, sizeof(firmware1)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex1, sizeof(findex1)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, firmware2, sizeof(firmware2)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, findex2, sizeof(findex2)); - vicam_sndctrl(1, vicam, VICAM_REQ_VENDOR, 0, fsetup, sizeof(fsetup)); - - vicam_parameters(vicam); - - FILL_BULK_URB(vicam->readurb, vicam->udev, usb_rcvbulkpipe(vicam->udev, 0x81), - buf, 0x1e480, vicam_bulk, vicam); - printk(KERN_DEBUG "Submiting urb: %d\n", usb_submit_urb(vicam->readurb, GFP_KERNEL)); + sprintf(name, "video%d", cam->vdev.minor); + remove_proc_entry(name, vicam_proc_root); + cam->proc_entry = NULL; +} + +#endif + +int +vicam_video_init(struct video_device *vdev) +{ + // This would normally create the proc entry for this camera +#ifdef CONFIG_PROC_FS + vicam_create_proc_entry(vdev->priv); +#endif return 0; -error: - if (buf) - kfree(buf); - if (buf2) - kfree(buf2); - return 1; -} - -static int vicam_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_vicam *vicam; - char *camera_name=NULL; +} - dbg("vicam_probe"); +static struct file_operations vicam_fops = { + .owner = THIS_MODULE, + .open = vicam_open, + .release =vicam_close, + .read = vicam_read, + .mmap = vicam_mmap, + .ioctl = vicam_ioctl, + .llseek = no_llseek, +}; +static struct video_device vicam_template = { + .owner = THIS_MODULE, + .name = "ViCam-based USB Camera", + .type = VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_VICAM, + .fops = &vicam_fops, +// .initialize = vicam_video_init, + .minor = -1, +}; + +/* table of devices that work with this driver */ +static struct usb_device_id vicam_table[] = { + {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, vicam_table); + +static struct usb_driver vicam_driver = { + name:"vicam", + probe:vicam_probe, + disconnect:vicam_disconnect, + id_table:vicam_table +}; + +/** + * vicam_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int +vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + int bulkEndpoint = 0; + const struct usb_interface_descriptor *interface; + const struct usb_endpoint_descriptor *endpoint; + struct vicam_camera *cam; + /* See if the device offered us matches what we can accept */ - if ((udev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || - (udev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { + if ((dev->descriptor.idVendor != USB_VICAM_VENDOR_ID) || + (dev->descriptor.idProduct != USB_VICAM_PRODUCT_ID)) { return -ENODEV; } - - camera_name="3Com HomeConnect USB"; - info("ViCAM camera found: %s", camera_name); - - vicam = kmalloc (sizeof(struct usb_vicam), GFP_KERNEL); - if (vicam == NULL) { - err ("couldn't kmalloc vicam struct"); - return -ENOMEM; - } - memset(vicam, 0, sizeof(*vicam)); - vicam->readurb = usb_alloc_urb(0, GFP_KERNEL); - if (!vicam->readurb) { - kfree(vicam); - return -ENOMEM; + printk(KERN_INFO "ViCam based webcam connected\n"); + + interface = &intf->altsetting[0]; + + DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n", + ifnum, (unsigned) (interface->bNumEndpoints)); + endpoint = &interface->endpoint[0]; + + if ((endpoint->bEndpointAddress & 0x80) && + ((endpoint->bmAttributes & 3) == 0x02)) { + /* we found a bulk in endpoint */ + bulkEndpoint = endpoint->bEndpointAddress; + } else { + printk(KERN_ERR + "No bulk in endpoint was found ?! (this is bad)\n"); } - vicam->udev = udev; - vicam->camera_name = camera_name; - vicam->win.brightness = 128; - vicam->win.contrast = 10; - - /* FIXME */ - if (vicam_init(vicam)) { - usb_free_urb(vicam->readurb); - kfree(vicam); + if ((cam = + kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) { + printk(KERN_WARNING + "could not allocate kernel memory for vicam_camera struct\n"); return -ENOMEM; } - memcpy(&vicam->vdev, &vicam_template, sizeof(vicam_template)); - memcpy(vicam->vdev.name, vicam->camera_name, strlen(vicam->camera_name)); - - if (video_register_device(&vicam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { - err("video_register_device"); - usb_free_urb(vicam->readurb); - kfree(vicam); - return -EIO; - } - info("registered new video device: video%d", vicam->vdev.minor); - - init_MUTEX (&vicam->sem); - init_waitqueue_head(&vicam->wait); - - dev_set_drvdata (&intf->dev, vicam); - return 0; -} + memset(cam, 0, sizeof (struct vicam_camera)); + cam->shutter_speed = 15; -/* FIXME - vicam_disconnect - important */ -static void vicam_disconnect(struct usb_interface *intf) -{ - struct usb_vicam *vicam; + init_MUTEX(&cam->busy_lock); - vicam = dev_get_drvdata (&intf->dev); + memcpy(&cam->vdev, &vicam_template, + sizeof (vicam_template)); + cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only - dev_set_drvdata (&intf->dev, NULL); + cam->udev = dev; + cam->bulkEndpoint = bulkEndpoint; - if (vicam) { - video_unregister_device(&vicam->vdev); - vicam->udev = NULL; -/* - vicam->frame[0].grabstate = FRAME_ERROR; - vicam->frame[1].grabstate = FRAME_ERROR; -*/ + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { + kfree(cam); + printk(KERN_WARNING "video_register_device failed\n"); + return -EIO; + } - /* Free buffers and shit */ - info("%s disconnected", vicam->camera_name); - synchronize(vicam); + printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor); - if (!vicam->open_count) { - /* Other random junk */ - usb_free_urb(vicam->readurb); - kfree(vicam); - vicam = NULL; - } - } + dev_set_drvdata(&intf->dev, cam); + + return 0; } -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver vicam_driver = { - .owner = THIS_MODULE, - .name = "vicam", - .probe = vicam_probe, - .disconnect = vicam_disconnect, - .id_table = vicam_table, -}; +static void +vicam_disconnect(struct usb_interface *intf) +{ + struct vicam_camera *cam = dev_get_drvdata(&intf->dev); -/****************************************************************************** - * - * Module Routines - * - ******************************************************************************/ + dev_set_drvdata ( &intf->dev, NULL ); + usb_put_dev(cam->udev); + + cam->udev = NULL; + + video_unregister_device(&cam->vdev); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); +#ifdef CONFIG_PROC_FS + vicam_destroy_proc_entry(cam); +#endif -/* Module paramaters */ -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debug enabled or not"); + if (cam->raw_image) + kfree(cam->raw_image); + if (cam->framebuf) + rvfree(cam->framebuf, + VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); -static int __init usb_vicam_init(void) -{ - int result; + kfree(cam); - printk("VICAM: initializing\n"); - /* register this driver with the USB subsystem */ - result = usb_register(&vicam_driver); - if (result < 0) { - err("usb_register failed for the "__FILE__" driver. Error number %d", - result); - return -1; - } + printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); +} - info(DRIVER_VERSION " " DRIVER_AUTHOR); - info(DRIVER_DESC); +/* + */ +static int __init +usb_vicam_init(void) +{ + DBG(KERN_INFO "ViCam-based WebCam driver startup\n"); +#ifdef CONFIG_PROC_FS + vicam_create_proc_root(); +#endif + if (usb_register(&vicam_driver) != 0) + printk(KERN_WARNING "usb_register failed!\n"); return 0; } -static void __exit usb_vicam_exit(void) +static void __exit +usb_vicam_exit(void) { - /* deregister this driver with the USB subsystem */ + DBG(KERN_INFO + "ViCam-based WebCam driver shutdown\n"); + usb_deregister(&vicam_driver); +#ifdef CONFIG_PROC_FS + vicam_destroy_proc_root(); +#endif } module_init(usb_vicam_init); module_exit(usb_vicam_exit); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/usb/media/vicam.h b/drivers/usb/media/vicam.h --- a/drivers/usb/media/vicam.h Tue Oct 15 20:29:12 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,81 +0,0 @@ -/* - * - * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver - * Christopher L Cheney (C) 2001 - * - */ - -#ifndef __LINUX_VICAM_H -#define __LINUX_VICAM_H - - -#ifdef CONFIG_USB_DEBUG - static int debug = 1; -#else - static int debug; -#endif - -/* Use our own dbg macro */ -#undef dbg -#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg); } while (0) - -#define VICAM_NUMFRAMES 30 -#define VICAM_NUMSBUF 1 - -/* USB REQUEST NUMBERS */ -#define VICAM_REQ_VENDOR 0xff -#define VICAM_REQ_CAMERA_POWER 0x50 -#define VICAM_REQ_CAPTURE 0x51 -#define VICAM_REQ_LED_CONTROL 0x55 -#define VICAM_REQ_GET_SOMETHIN 0x56 - -/* not required but lets you know camera is on */ -/* camera must be on to turn on led */ -/* 0x01 always on 0x03 on when picture taken (flashes) */ - -struct picture_parm -{ - int width; - int height; - int brightness; - int hue; - int colour; - int contrast; - int whiteness; - int depth; - int palette; -}; - -struct vicam_scratch { - unsigned char *data; - volatile int state; - int offset; - int length; -}; - -/* Structure to hold all of our device specific stuff */ -struct usb_vicam -{ - struct video_device vdev; - struct usb_device *udev; - - int open_count; /* number of times this port has been opened */ - struct semaphore sem; /* locks this structure */ - wait_queue_head_t wait; /* Processes waiting */ - - int streaming; - - /* v4l stuff */ - char *camera_name; - char *fbuf; - struct urb *urb[VICAM_NUMSBUF]; - int sizes; - int *width; - int *height; - int maxframesize; - struct picture_parm win; - struct proc_dir_entry *proc_entry; /* /proc/se401/videoX */ - struct urb *readurb; -}; - -#endif diff -Nru a/drivers/usb/media/vicamurbs.h b/drivers/usb/media/vicamurbs.h --- a/drivers/usb/media/vicamurbs.h Tue Oct 15 20:29:15 2002 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,332 +0,0 @@ -/* - * - * Vista Imaging ViCAM / 3Com HomeConnect Usermode Driver - * Christopher L Cheney (C) 2001 - * - */ - - -#ifndef __LINUX_VICAMURBS_H -#define __LINUX_VICAMURBS_H - -/* -------------------------------------------------------------------------- */ - -/* FIXME - Figure out transfers so that this doesn't need to be here - * - * Notice: in pieces below, "0" means other code will fill it while "0x00" means this is zero */ - -/* Request 0x51 Image Setup */ - -#if 0 -/* 128x98 ? 0x3180 size */ -static unsigned char s128x98bw[] = { - 0, 0x34, 0xC4, 0x00, 0x00, 0x00, 0, 0, - 0x18, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; -#endif - -/* 128x122 3D80 size */ -static unsigned char s128x122bw[] = { - 0, 0x34, 0xF4, 0x00, 0x00, 0x00, 0, 0, - 0x00, 0x02, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* 256x242 ? 0xF280 size */ -static unsigned char s256x242bw[] = { - 0, 0x03, 0xC8, 0x03, 0x00, 0x00, 0, 0, - 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* 512x242 0x1E480 size */ -static unsigned char s512x242bw[] = { - 0, 0x05, 0x90, 0x07, 0x00, 0x00, 0, 0, - 0x00, 0x08, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00 -}; - -/* In s512x242: - byte 0: gain -- higher number means brighter image - byte 6, 7: shutter speed, little-endian; set this to 15600 * (shutter speed) - 1. (Where shutter speed is something like 1/1000). -*/ - -/* -------------------------------------------------------------------------- */ - -static unsigned char fsetup[] = { - 0xB6, 0xC3, 0x01, 0x00, 0x06, 0x64, - - 0x00, 0x00 -}; - -static unsigned char firmware1[] = { - 0xB6, 0xC3, 0x1F, 0x00, 0x02, 0x64, - - 0xE7, 0x67, 0xFD, 0xFF, 0x0E, 0xC0, 0xE7, 0x09, - 0xDE, 0x00, 0x8E, 0x00, 0xC0, 0x09, 0x40, 0x03, - 0xC0, 0x17, 0x44, 0x03, 0x4B, 0xAF, 0xC0, 0x07, - 0x00, 0x00, 0x4B, 0xAF, 0x97, 0xCF, 0x00, 0x00 -}; - -static unsigned char findex1[] = { - 0xB6, 0xC3, 0x03, 0x00, 0x03, 0x64, - - 0x18, 0x00, 0x00, 0x00 -}; - -static unsigned char firmware2[] = { - 0xB6, 0xC3, 0x8F, 0x06, 0x02, 0x64, - - 0xE7, 0x07, 0x00, 0x00, 0x08, 0xC0, 0xE7, 0x07, - 0x00, 0x00, 0x3E, 0xC0, 0xE7, 0x07, 0x54, 0x01, - 0xAA, 0x00, 0xE7, 0x07, 0xC8, 0x05, 0xB6, 0x00, - 0xE7, 0x07, 0x42, 0x01, 0xD2, 0x00, 0xE7, 0x07, - 0x7C, 0x00, 0x16, 0x00, 0xE7, 0x07, 0x56, 0x00, - 0x18, 0x00, 0xE7, 0x07, 0x06, 0x00, 0x92, 0xC0, - 0xE7, 0x07, 0x00, 0x00, 0x1E, 0xC0, 0xE7, 0x07, - 0xFF, 0xFF, 0x22, 0xC0, 0xE7, 0x07, 0x04, 0x00, - 0x24, 0xC0, 0xE7, 0x07, 0xEC, 0x27, 0x28, 0xC0, - 0xE7, 0x07, 0x16, 0x01, 0x8E, 0x00, 0xE7, 0x87, - 0x01, 0x00, 0x0E, 0xC0, 0x97, 0xCF, 0xD7, 0x09, - 0x00, 0xC0, 0xE7, 0x77, 0x01, 0x00, 0x92, 0xC0, - 0x09, 0xC1, 0xE7, 0x09, 0xFE, 0x05, 0x24, 0x01, - 0xE7, 0x09, 0x04, 0x06, 0x26, 0x01, 0xE7, 0x07, - 0x07, 0x00, 0x92, 0xC0, 0xE7, 0x05, 0x00, 0xC0, - 0xC0, 0xDF, 0x97, 0xCF, 0x17, 0x00, 0x57, 0x00, - 0x17, 0x02, 0xD7, 0x09, 0x00, 0xC0, 0xE7, 0x77, - 0x01, 0x00, 0x92, 0xC0, 0x0A, 0xC1, 0xE7, 0x57, - 0xFF, 0xFF, 0xFA, 0x05, 0x0D, 0xC0, 0xE7, 0x57, - 0x00, 0x00, 0xFA, 0x05, 0x0F, 0xC0, 0x9F, 0xAF, - 0xC6, 0x00, 0xE7, 0x05, 0x00, 0xC0, 0xC8, 0x05, - 0xC1, 0x05, 0xC0, 0x05, 0xC0, 0xDF, 0x97, 0xCF, - 0x27, 0xDA, 0xFA, 0x05, 0xEF, 0x07, 0x01, 0x00, - 0x0B, 0x06, 0x73, 0xCF, 0x9F, 0xAF, 0x78, 0x01, - 0x9F, 0xAF, 0x1A, 0x03, 0x6E, 0xCF, 0xE7, 0x09, - 0xFC, 0x05, 0x24, 0x01, 0xE7, 0x09, 0x02, 0x06, - 0x26, 0x01, 0xE7, 0x07, 0x07, 0x00, 0x92, 0xC0, - 0xE7, 0x09, 0xFC, 0x05, 0xFE, 0x05, 0xE7, 0x09, - 0x02, 0x06, 0x04, 0x06, 0xE7, 0x09, 0x00, 0x06, - 0xFC, 0x05, 0xE7, 0x09, 0xFE, 0x05, 0x00, 0x06, - 0x27, 0xDA, 0xFA, 0x05, 0xE7, 0x57, 0x01, 0x00, - 0xFA, 0x05, 0x02, 0xCA, 0x04, 0xC0, 0x97, 0xCF, - 0x9F, 0xAF, 0x66, 0x05, 0x97, 0xCF, 0xE7, 0x07, - 0x40, 0x00, 0x02, 0x06, 0xC8, 0x09, 0xFC, 0x05, - 0x9F, 0xAF, 0xDA, 0x02, 0x97, 0xCF, 0xCF, 0x17, - 0x02, 0x00, 0xEF, 0x57, 0x81, 0x00, 0x09, 0x06, - 0x9F, 0xA0, 0xB6, 0x01, 0xEF, 0x57, 0x80, 0x00, - 0x09, 0x06, 0x9F, 0xA0, 0x40, 0x02, 0xEF, 0x57, - 0x01, 0x00, 0x0B, 0x06, 0x9F, 0xA0, 0x46, 0x03, - 0xE7, 0x07, 0x01, 0x00, 0x0A, 0xC0, 0x46, 0xAF, - 0x47, 0xAF, 0x9F, 0xAF, 0x40, 0x02, 0xE7, 0x07, - 0x2E, 0x00, 0x0A, 0xC0, 0xEF, 0x87, 0x80, 0x00, - 0x09, 0x06, 0x97, 0xCF, 0x00, 0x0E, 0x01, 0x00, - 0xC0, 0x57, 0x51, 0x00, 0x9F, 0xC0, 0x9E, 0x02, - 0xC0, 0x57, 0x50, 0x00, 0x20, 0xC0, 0xC0, 0x57, - 0x55, 0x00, 0x12, 0xC0, 0xC0, 0x57, 0x56, 0x00, - 0x9F, 0xC0, 0x72, 0x02, 0x9F, 0xCF, 0xD6, 0x02, - 0xC1, 0x0B, 0x08, 0x06, 0x01, 0xD0, 0x6F, 0x90, - 0x08, 0x06, 0xC0, 0x07, 0x08, 0x00, 0xC1, 0x0B, - 0x08, 0x06, 0x9F, 0xAF, 0x28, 0x05, 0x97, 0xCF, - 0x2F, 0x0E, 0x02, 0x00, 0x08, 0x06, 0xC0, 0x07, - 0x08, 0x00, 0xC1, 0x0B, 0x08, 0x06, 0x9F, 0xAF, - 0x28, 0x05, 0x9F, 0xCF, 0xD6, 0x02, 0x2F, 0x0E, - 0x02, 0x00, 0x09, 0x06, 0xEF, 0x87, 0x80, 0x00, - 0x09, 0x06, 0x9F, 0xCF, 0xD6, 0x02, 0xEF, 0x67, - 0x7F, 0xFF, 0x09, 0x06, 0xE7, 0x67, 0xFF, 0xFD, - 0x22, 0xC0, 0xE7, 0x67, 0xEF, 0xFF, 0x24, 0xC0, - 0xE7, 0x87, 0x10, 0x00, 0x28, 0xC0, 0x9F, 0xAF, - 0xB8, 0x05, 0xE7, 0x87, 0xE0, 0x21, 0x24, 0xC0, - 0x9F, 0xAF, 0xA8, 0x05, 0xE7, 0x87, 0x08, 0x00, - 0x24, 0xC0, 0xE7, 0x67, 0xDF, 0xFF, 0x24, 0xC0, - 0xC8, 0x07, 0x0A, 0x00, 0xC0, 0x07, 0x00, 0x00, - 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0x9F, 0xAF, 0xB8, 0x05, 0xC0, 0x07, 0x9E, 0x00, - 0x9F, 0xAF, 0x44, 0x05, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xC0, 0x09, 0x20, 0xC0, 0xE7, 0x87, - 0x00, 0x01, 0x24, 0xC0, 0xC0, 0x77, 0x00, 0x02, - 0x0F, 0xC1, 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, - 0xE7, 0x67, 0xF7, 0xFF, 0x24, 0xC0, 0xE7, 0x87, - 0x08, 0x00, 0x24, 0xC0, 0x08, 0xDA, 0x5E, 0xC1, - 0xEF, 0x07, 0x80, 0x00, 0x09, 0x06, 0x97, 0xCF, - 0xEF, 0x07, 0x01, 0x00, 0x0A, 0x06, 0x97, 0xCF, - 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xEF, 0x07, - 0x00, 0x00, 0x0A, 0x06, 0xEF, 0x67, 0x7F, 0xFF, - 0x09, 0x06, 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, - 0xE7, 0x67, 0xEF, 0xFF, 0x28, 0xC0, 0xE7, 0x67, - 0x17, 0xD8, 0x24, 0xC0, 0xE7, 0x07, 0x00, 0x00, - 0x1E, 0xC0, 0xE7, 0x07, 0xFF, 0xFF, 0x22, 0xC0, - 0x97, 0xCF, 0xC8, 0x07, 0x0E, 0x06, 0x9F, 0xAF, - 0xDA, 0x02, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, - 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, - 0x0E, 0x06, 0xF4, 0x05, 0xE7, 0x07, 0xD6, 0x02, - 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, - 0x00, 0x80, 0x50, 0xAF, 0x97, 0xCF, 0x2F, 0x0C, - 0x02, 0x00, 0x07, 0x06, 0x2F, 0x0C, 0x04, 0x00, - 0x06, 0x06, 0xE7, 0x07, 0x00, 0x00, 0xF2, 0x05, - 0xE7, 0x07, 0x10, 0x00, 0xF6, 0x05, 0xE7, 0x07, - 0xE2, 0x05, 0xF4, 0x05, 0xE7, 0x07, 0xCE, 0x02, - 0xF8, 0x05, 0xC8, 0x07, 0xF2, 0x05, 0xC1, 0x07, - 0x00, 0x80, 0x51, 0xAF, 0x97, 0xCF, 0x9F, 0xAF, - 0x66, 0x04, 0x9F, 0xAF, 0x1A, 0x03, 0x59, 0xAF, - 0x97, 0xCF, 0xC0, 0x07, 0x0E, 0x00, 0xC1, 0x0B, - 0x0C, 0x06, 0x41, 0xD1, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x3C, 0x00, 0x9F, 0xAF, 0x44, 0x05, - 0x68, 0x00, 0xC0, 0x07, 0x3B, 0x00, 0x9F, 0xAF, - 0x44, 0x05, 0x6F, 0x00, 0x0C, 0x06, 0x68, 0x00, - 0xE0, 0x07, 0x04, 0x01, 0xE8, 0x0B, 0x0A, 0x06, - 0xE8, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x02, - 0xE0, 0x07, 0xEC, 0x01, 0xE0, 0x07, 0xFC, 0xFF, - 0x97, 0xCF, 0xE7, 0x07, 0xFF, 0xFF, 0xFA, 0x05, - 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x06, 0xE7, 0x07, - 0x0E, 0x06, 0x24, 0x01, 0xE7, 0x07, 0x0E, 0x06, - 0xFE, 0x05, 0xE7, 0x07, 0x40, 0x00, 0x26, 0x01, - 0xE7, 0x07, 0x40, 0x00, 0x04, 0x06, 0xE7, 0x07, - 0x07, 0x00, 0x92, 0xC0, 0x97, 0xCF, 0xEF, 0x07, - 0x02, 0x00, 0x0B, 0x06, 0x9F, 0xAF, 0x78, 0x01, - 0xEF, 0x77, 0x80, 0x00, 0x07, 0x06, 0x9F, 0xC0, - 0x14, 0x04, 0xEF, 0x77, 0x01, 0x00, 0x07, 0x06, - 0x37, 0xC0, 0xEF, 0x77, 0x01, 0x00, 0x0D, 0x06, - 0x0F, 0xC1, 0xEF, 0x07, 0x01, 0x00, 0x0D, 0x06, - 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, 0x30, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x01, 0x00, - 0xC1, 0x07, 0x02, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xC8, 0x07, 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, - 0xC0, 0x07, 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, - 0xC1, 0x77, 0x03, 0x00, 0x02, 0xC1, 0x08, 0xDA, - 0x75, 0xC1, 0xC1, 0x77, 0x01, 0x00, 0x0A, 0xC1, - 0xC0, 0x07, 0x01, 0x00, 0xC1, 0x07, 0x02, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xEF, 0x07, 0x01, 0x00, - 0x06, 0x06, 0x2C, 0xCF, 0xC0, 0x07, 0x01, 0x00, - 0xC1, 0x07, 0x04, 0x00, 0x9F, 0xAF, 0x28, 0x05, - 0xEF, 0x07, 0x00, 0x00, 0x06, 0x06, 0x22, 0xCF, - 0xEF, 0x07, 0x00, 0x00, 0x0D, 0x06, 0xEF, 0x57, - 0x01, 0x00, 0x06, 0x06, 0x1B, 0xC0, 0xC0, 0x07, - 0x01, 0x00, 0xC1, 0x07, 0x01, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x02, 0x00, 0xC1, 0x07, - 0x30, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC8, 0x07, - 0xFF, 0x4F, 0x9F, 0xAF, 0xA8, 0x05, 0xC0, 0x07, - 0x38, 0x00, 0x9F, 0xAF, 0x44, 0x05, 0xC1, 0x67, - 0x03, 0x00, 0xC1, 0x57, 0x03, 0x00, 0x02, 0xC0, - 0x08, 0xDA, 0x73, 0xC1, 0xC0, 0x07, 0x02, 0x00, - 0xC1, 0x07, 0x12, 0x00, 0xEF, 0x57, 0x00, 0x00, - 0x06, 0x06, 0x02, 0xC0, 0xC1, 0x07, 0x23, 0x00, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x14, 0x00, - 0xC1, 0x0B, 0xEA, 0x05, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x3E, 0x00, 0x9F, 0xAF, 0x0A, 0x05, - 0xE7, 0x09, 0xE4, 0x05, 0xFA, 0x05, 0x27, 0xD8, - 0xFA, 0x05, 0xE7, 0x07, 0x0E, 0x06, 0xFC, 0x05, - 0xE7, 0x07, 0x4E, 0x06, 0x00, 0x06, 0xE7, 0x07, - 0x40, 0x00, 0x02, 0x06, 0x9F, 0xAF, 0x66, 0x05, - 0x9F, 0xAF, 0xC6, 0x00, 0x97, 0xCF, 0xC1, 0x0B, - 0xE2, 0x05, 0x41, 0xD0, 0x01, 0xD2, 0xC1, 0x17, - 0x23, 0x00, 0x9F, 0xAF, 0xDC, 0x04, 0xC0, 0x07, - 0x04, 0x00, 0xC1, 0x0B, 0xE3, 0x05, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x06, 0x00, 0xC1, 0x09, - 0xE6, 0x05, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x07, 0x00, 0xC1, 0x09, 0xE6, 0x05, 0xC1, 0xD1, - 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, 0x0B, 0x00, - 0xC1, 0x09, 0xE8, 0x05, 0x9F, 0xAF, 0x28, 0x05, - 0xC0, 0x07, 0x0C, 0x00, 0xC1, 0x09, 0xE8, 0x05, - 0xC1, 0xD1, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x0D, 0x00, 0xC1, 0x07, 0x09, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0xC0, 0x07, 0x03, 0x00, 0xC1, 0x07, - 0x32, 0x00, 0x9F, 0xAF, 0x28, 0x05, 0xC0, 0x07, - 0x0F, 0x00, 0xC1, 0x07, 0x00, 0x00, 0x9F, 0xAF, - 0x28, 0x05, 0x97, 0xCF, 0xE7, 0x67, 0xFF, 0xD9, - 0x24, 0xC0, 0xC8, 0x07, 0x0A, 0x00, 0x40, 0x00, - 0xC0, 0x67, 0x00, 0x02, 0x27, 0x80, 0x24, 0xC0, - 0xE7, 0x87, 0x00, 0x04, 0x24, 0xC0, 0xE7, 0x67, - 0xFF, 0xF9, 0x24, 0xC0, 0x01, 0xD2, 0x08, 0xDA, - 0x72, 0xC1, 0xE7, 0x87, 0x00, 0x20, 0x24, 0xC0, - 0x97, 0xCF, 0x27, 0x00, 0x1E, 0xC0, 0xE7, 0x87, - 0xFF, 0x00, 0x22, 0xC0, 0xE7, 0x67, 0x7F, 0xFF, - 0x24, 0xC0, 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, - 0xE7, 0x87, 0x80, 0x00, 0x24, 0xC0, 0x97, 0xCF, - 0x9F, 0xAF, 0x0A, 0x05, 0x67, 0x00, 0x1E, 0xC0, - 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0xE7, 0x87, - 0x40, 0x00, 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, - 0x24, 0xC0, 0x97, 0xCF, 0x9F, 0xAF, 0x0A, 0x05, - 0xE7, 0x67, 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, - 0xFF, 0xFE, 0x24, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xC1, 0x09, 0x20, 0xC0, 0xE7, 0x87, - 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, 0xC0, 0x07, - 0x40, 0x00, 0xC8, 0x09, 0xFC, 0x05, 0xE7, 0x67, - 0x00, 0xFF, 0x22, 0xC0, 0xE7, 0x67, 0xFF, 0xFE, - 0x24, 0xC0, 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, - 0xE7, 0x67, 0xBF, 0xFF, 0x24, 0xC0, 0x00, 0xDA, - 0xE8, 0x09, 0x20, 0xC0, 0xE7, 0x87, 0x40, 0x00, - 0x24, 0xC0, 0xE7, 0x87, 0x40, 0x00, 0x24, 0xC0, - 0x00, 0xDA, 0xE8, 0x09, 0x20, 0xC0, 0x6D, 0xC1, - 0xE7, 0x87, 0x00, 0x01, 0x24, 0xC0, 0x97, 0xCF, - 0xE7, 0x07, 0x32, 0x00, 0x12, 0xC0, 0xE7, 0x77, - 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, - 0xE7, 0x07, 0x20, 0x4E, 0x12, 0xC0, 0xE7, 0x77, - 0x00, 0x80, 0x12, 0xC0, 0x7C, 0xC0, 0x97, 0xCF, - 0x09, 0x02, 0x19, 0x00, 0x01, 0x01, 0x00, 0x80, - 0x96, 0x09, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static unsigned char findex2[] = { - 0xB6, 0xC3, 0x2F, 0x01, 0x03, 0x64, - - 0x0E, 0x00, 0x14, 0x00, 0x1A, 0x00, 0x20, 0x00, - 0x26, 0x00, 0x4A, 0x00, 0x64, 0x00, 0x6A, 0x00, - 0x92, 0x00, 0x9A, 0x00, 0xA0, 0x00, 0xB2, 0x00, - 0xB8, 0x00, 0xBE, 0x00, 0xC2, 0x00, 0xC8, 0x00, - 0xCE, 0x00, 0xDC, 0x00, 0xDA, 0x00, 0xE2, 0x00, - 0xE0, 0x00, 0xE8, 0x00, 0xE6, 0x00, 0xEE, 0x00, - 0xEC, 0x00, 0xF2, 0x00, 0xF8, 0x00, 0x02, 0x01, - 0x0A, 0x01, 0x0E, 0x01, 0x12, 0x01, 0x1E, 0x01, - 0x22, 0x01, 0x28, 0x01, 0x2C, 0x01, 0x32, 0x01, - 0x36, 0x01, 0x44, 0x01, 0x50, 0x01, 0x5E, 0x01, - 0x72, 0x01, 0x76, 0x01, 0x7A, 0x01, 0x80, 0x01, - 0x88, 0x01, 0x8C, 0x01, 0x94, 0x01, 0x9C, 0x01, - 0xA0, 0x01, 0xA4, 0x01, 0xAA, 0x01, 0xB0, 0x01, - 0xB4, 0x01, 0xBA, 0x01, 0xD0, 0x01, 0xDA, 0x01, - 0xF6, 0x01, 0xFA, 0x01, 0x02, 0x02, 0x34, 0x02, - 0x3C, 0x02, 0x44, 0x02, 0x4A, 0x02, 0x50, 0x02, - 0x56, 0x02, 0x74, 0x02, 0x78, 0x02, 0x7E, 0x02, - 0x84, 0x02, 0x8A, 0x02, 0x88, 0x02, 0x90, 0x02, - 0x8E, 0x02, 0x94, 0x02, 0xA2, 0x02, 0xA8, 0x02, - 0xAE, 0x02, 0xB4, 0x02, 0xBA, 0x02, 0xB8, 0x02, - 0xC0, 0x02, 0xBE, 0x02, 0xC4, 0x02, 0xD0, 0x02, - 0xD4, 0x02, 0xE0, 0x02, 0xE6, 0x02, 0xEE, 0x02, - 0xF8, 0x02, 0xFC, 0x02, 0x06, 0x03, 0x1E, 0x03, - 0x24, 0x03, 0x28, 0x03, 0x30, 0x03, 0x2E, 0x03, - 0x3C, 0x03, 0x4A, 0x03, 0x4E, 0x03, 0x54, 0x03, - 0x58, 0x03, 0x5E, 0x03, 0x66, 0x03, 0x6E, 0x03, - 0x7A, 0x03, 0x86, 0x03, 0x8E, 0x03, 0x96, 0x03, - 0xB2, 0x03, 0xB8, 0x03, 0xC6, 0x03, 0xCC, 0x03, - 0xD4, 0x03, 0xDA, 0x03, 0xE8, 0x03, 0xF4, 0x03, - 0xFC, 0x03, 0x04, 0x04, 0x20, 0x04, 0x2A, 0x04, - 0x32, 0x04, 0x36, 0x04, 0x3E, 0x04, 0x44, 0x04, - 0x42, 0x04, 0x48, 0x04, 0x4E, 0x04, 0x4C, 0x04, - 0x54, 0x04, 0x52, 0x04, 0x5A, 0x04, 0x5E, 0x04, - 0x62, 0x04, 0x68, 0x04, 0x74, 0x04, 0x7C, 0x04, - 0x80, 0x04, 0x88, 0x04, 0x8C, 0x04, 0x94, 0x04, - 0x9A, 0x04, 0xA2, 0x04, 0xA6, 0x04, 0xAE, 0x04, - 0xB4, 0x04, 0xC0, 0x04, 0xCC, 0x04, 0xD8, 0x04, - 0x2A, 0x05, 0x46, 0x05, 0x6C, 0x05, 0x00, 0x00 -}; - -#endif diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/net/usbnet.c Tue Oct 15 20:29:17 2002 @@ -2092,7 +2092,7 @@ #ifdef CONFIG_USB_EPSON2888 { USB_DEVICE (0x0525, 0x2888), // EPSON USB client - driver_info: (unsigned long) &epson2888_info, + .driver_info = (unsigned long) &epson2888_info, }, #endif diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- a/drivers/usb/serial/io_ti.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/serial/io_ti.c Tue Oct 15 20:29:16 2002 @@ -2617,47 +2617,47 @@ static struct usb_serial_device_type edgeport_1port_device = { - owner: THIS_MODULE, - name: "Edgeport TI 1 port adapter", - id_table: edgeport_1port_id_table, - num_interrupt_in: 1, - num_bulk_in: 1, - num_bulk_out: 1, - num_ports: 1, - open: edge_open, - close: edge_close, - throttle: edge_throttle, - unthrottle: edge_unthrottle, - attach: edge_startup, - shutdown: edge_shutdown, - ioctl: edge_ioctl, - set_termios: edge_set_termios, - write: edge_write, - write_room: edge_write_room, - chars_in_buffer: edge_chars_in_buffer, - break_ctl: edge_break, + .owner = THIS_MODULE, + .name = "Edgeport TI 1 port adapter", + .id_table = edgeport_1port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, }; static struct usb_serial_device_type edgeport_2port_device = { - owner: THIS_MODULE, - name: "Edgeport TI 2 port adapter", - id_table: edgeport_2port_id_table, - num_interrupt_in: 1, - num_bulk_in: 2, - num_bulk_out: 2, - num_ports: 2, - open: edge_open, - close: edge_close, - throttle: edge_throttle, - unthrottle: edge_unthrottle, - attach: edge_startup, - shutdown: edge_shutdown, - ioctl: edge_ioctl, - set_termios: edge_set_termios, - write: edge_write, - write_room: edge_write_room, - chars_in_buffer: edge_chars_in_buffer, - break_ctl: edge_break, + .owner = THIS_MODULE, + .name = "Edgeport TI 2 port adapter", + .id_table = edgeport_2port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 2, + .num_bulk_out = 2, + .num_ports = 2, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .shutdown = edge_shutdown, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, }; diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/serial/usb-serial.c Tue Oct 15 20:29:16 2002 @@ -1237,16 +1237,17 @@ } #if defined(CONFIG_USB_SERIAL_PL2303) || defined(CONFIG_USB_SERIAL_PL2303_MODULE) -#if 0 /* BEGIN HORRIBLE HACK FOR PL2303 */ /* this is needed due to the looney way its endpoints are set up */ - if (ifnum == 1) { - if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) && - (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || - ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && - (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { + if (((dev->descriptor.idVendor == PL2303_VENDOR_ID) && + (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || + ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && + (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { + //if (ifnum == 1) { + if (interface != &dev->actconfig->interface[0]) { /* check out the endpoints of the other interface*/ - interface = &dev->actconfig->interface[ifnum ^ 1]; + //interface = &dev->actconfig->interface[ifnum ^ 1]; + interface = &dev->actconfig->interface[0]; iface_desc = &interface->altsetting[0]; for (i = 0; i < iface_desc->bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i]; @@ -1259,9 +1260,18 @@ } } } + + /* Now make sure the PL-2303 is configured correctly. + * If not, give up now and hope this hack will work + * properly during a later invocation of usb_serial_probe + */ + if (num_bulk_in == 0 || num_bulk_out == 0) { + info("PL-2303 hack: descriptors matched but endpoints did not"); + kfree (serial); + return -ENODEV; + } } /* END HORRIBLE HACK FOR PL2303 */ -#endif #endif /* found all that we need */ diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Tue Oct 15 20:29:15 2002 +++ b/drivers/usb/serial/visor.c Tue Oct 15 20:29:15 2002 @@ -669,7 +669,7 @@ /* get the interface number */ result = usb_control_msg (serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQ_GET_INTERFACE, - USB_DIR_IN | USB_DT_DEVICE, + USB_DIR_IN | USB_RECIP_INTERFACE, 0, 0, &data, 1, HZ * 3); if (result < 0) { err("%s: get interface number failed: %d", __FUNCTION__, result); diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c --- a/drivers/usb/serial/whiteheat.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/serial/whiteheat.c Tue Oct 15 20:29:16 2002 @@ -334,6 +334,12 @@ command_port = &serial->port[COMMAND_PORT]; pipe = usb_sndbulkpipe (serial->dev, command_port->bulk_out_endpointAddress); + /* + * When the module is reloaded the firmware is still there and + * the endpoints are still in the usb core unchanged. This is the + * unlinking bug in disguise. Same for the call below. + */ + usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, command, sizeof(command), &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't send command [%d]", serial->type->name, ret); @@ -344,6 +350,8 @@ } pipe = usb_rcvbulkpipe (serial->dev, command_port->bulk_in_endpointAddress); + /* See the comment on the usb_clear_halt() above */ + usb_clear_halt(serial->dev, pipe); ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(result), &alen, COMMAND_TIMEOUT); if (ret) { err("%s: Couldn't get results [%d]", serial->type->name, ret); @@ -438,6 +446,10 @@ if (retval) goto exit; + /* Work around HCD bugs */ + usb_clear_halt(port->serial->dev, port->read_urb->pipe); + usb_clear_halt(port->serial->dev, port->write_urb->pipe); + /* Start reading from the device */ port->read_urb->dev = port->serial->dev; retval = usb_submit_urb(port->read_urb, GFP_KERNEL); @@ -489,7 +501,8 @@ { dbg("%s - port %d", __FUNCTION__, port->number); - if (tty_hung_up_p(filp)) { + /* filp is NULL when called from usb_serial_disconnect */ + if (filp && (tty_hung_up_p(filp))) { return; } @@ -1145,6 +1158,9 @@ command_info = (struct whiteheat_command_private *)command_port->private; spin_lock_irqsave(&command_info->lock, flags); if (!command_info->port_running) { + /* Work around HCD bugs */ + usb_clear_halt(serial->dev, command_port->read_urb->pipe); + command_port->read_urb->dev = serial->dev; retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL); if (retval) { diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c Tue Oct 15 20:29:23 2002 +++ b/drivers/usb/storage/datafab.c Tue Oct 15 20:29:23 2002 @@ -67,25 +67,23 @@ static inline int datafab_bulk_read(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("datafab_bulk_read: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, len, NULL); } static inline int datafab_bulk_write(struct us_data *us, unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("datafab_bulk_write: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + data, len, NULL); } @@ -522,6 +520,7 @@ 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO); if (!us->extra) { diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c --- a/drivers/usb/storage/freecom.c Tue Oct 15 20:29:23 2002 +++ b/drivers/usb/storage/freecom.c Tue Oct 15 20:29:23 2002 @@ -108,72 +108,9 @@ /* All packets (except for status) are 64 bytes long. */ #define FCM_PACKET_LENGTH 64 -/* - * Transfer an entire SCSI command's worth of data payload over the bulk - * pipe. - * - * Note that this uses usb_stor_transfer_partial to achieve it's goals -- this - * function simply determines if we're going to use scatter-gather or not, - * and acts appropriately. For now, it also re-interprets the error codes. - */ -static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount) -{ - int i; - int result = -1; - struct scatterlist *sg; - unsigned int total_transferred = 0; - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; - - /* are we scatter-gathering? */ - if (srb->use_sg) { - - /* loop over all the scatter gather structures and - * make the appropriate requests for each, until done - */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { - - US_DEBUGP("transfer_amount: %d and total_transferred: %d\n", transfer_amount, total_transferred); - - /* End this if we're done */ - if (transfer_amount == total_transferred) - break; - - /* transfer the lesser of the next buffer or the - * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); - total_transferred += transfer_amount - total_transferred; - } - - /* if we get an error, end the loop here */ - if (result) - break; - } - } - else - /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); - - /* return the result in the data structure itself */ - srb->result = result; -} - static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) + unsigned int ipipe, unsigned int opipe, int count) { freecom_udata_t extra = (freecom_udata_t) us->extra; struct freecom_xfer_wrap *fxfr = @@ -206,15 +143,15 @@ /* Now transfer all of our blocks. */ US_DEBUGP("Start of read\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, ipipe, srb, count); US_DEBUGP("freecom_readdata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } static int freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, - int ipipe, int opipe, int count) + int unsigned ipipe, unsigned int opipe, int count) { freecom_udata_t extra = (freecom_udata_t) us->extra; struct freecom_xfer_wrap *fxfr = @@ -248,10 +185,10 @@ /* Now transfer all of our blocks. */ US_DEBUGP("Start of write\n"); - us_transfer_freecom(srb, us, count); + result = usb_stor_bulk_transfer_srb(us, opipe, srb, count); US_DEBUGP("freecom_writedata done!\n"); - return USB_STOR_TRANSPORT_GOOD; + return result; } /* @@ -262,7 +199,7 @@ { struct freecom_cb_wrap *fcb; struct freecom_status *fst; - int ipipe, opipe; /* We need both pipes. */ + unsigned int ipipe, opipe; /* We need both pipes. */ int result; int partial; int length; @@ -276,8 +213,8 @@ US_DEBUGP("Freecom TRANSPORT STARTED\n"); /* Get handles for both transports. */ - opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); - ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); + opipe = us->send_bulk_pipe; + ipipe = us->recv_bulk_pipe; /* The ATAPI Command always goes out first. */ fcb->Type = FCM_PACKET_ATAPI | 0x00; @@ -515,8 +452,7 @@ } } - result = usb_control_msg(us->pusb_dev, - usb_rcvctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->recv_ctrl_pipe, 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); buffer[32] = '\0'; US_DEBUGP("String returned from FC init is: %s\n", buffer); @@ -528,8 +464,7 @@ */ /* send reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from activate reset is %d\n", result); @@ -537,8 +472,7 @@ mdelay(250); /* clear reset */ - result = usb_control_msg(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from clear reset is %d\n", result); diff -Nru a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c --- a/drivers/usb/storage/initializers.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/storage/initializers.c Tue Oct 15 20:29:16 2002 @@ -50,7 +50,7 @@ int result; US_DEBUGP("Attempting to init eUSCSI bridge...\n"); - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, 0x01, 0x0, &data, 0x1, 5*HZ); US_DEBUGP("-- result is %d\n", result); diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/storage/isd200.c Tue Oct 15 20:29:17 2002 @@ -408,13 +408,13 @@ { int result; int partial; - int pipe; + unsigned int pipe; /* calculate the appropriate pipe information */ if (dataDirection == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + pipe = us->recv_bulk_pipe; else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + pipe = us->send_bulk_pipe; /* transfer the data */ US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length); @@ -546,7 +546,6 @@ struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; int result; - int pipe; int partial; unsigned int transfer_amount; @@ -566,9 +565,6 @@ bcb.Length = AtaCdbLength; - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, AtaCdb, bcb.Length); @@ -578,8 +574,8 @@ le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0xFF), le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, + US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ @@ -589,8 +585,9 @@ else if (result == -EPIPE) { /* if we stall, we need to clear it before we go on */ - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - if (usb_stor_clear_halt(us, pipe) < 0) + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->send_bulk_pipe); + if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0) return ISD200_TRANSPORT_ERROR; } else if (result) return ISD200_TRANSPORT_ERROR; @@ -608,13 +605,10 @@ * an explanation of how this code works. */ - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, + US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { return ISD200_TRANSPORT_ABORTED; @@ -622,13 +616,14 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - if (usb_stor_clear_halt(us, pipe) < 0) + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->recv_bulk_pipe); + if (usb_stor_clear_halt(us, us->recv_bulk_pipe) < 0) return ISD200_TRANSPORT_ERROR; /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, US_BULK_CS_WRAP_LEN, &partial); /* if the command was aborted, indicate that */ @@ -638,8 +633,9 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing halt for pipe 0x%x\n", + us->recv_bulk_pipe); + usb_stor_clear_halt(us, us->recv_bulk_pipe); return ISD200_TRANSPORT_ERROR; } } @@ -937,7 +933,7 @@ /* let's send the command via the control pipe */ result = usb_stor_control_msg( us, - usb_sndctrlpipe(us->pusb_dev,0), + us->send_ctrl_pipe, 0x01, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, 0x0000, @@ -978,7 +974,7 @@ result = usb_stor_control_msg( us, - usb_rcvctrlpipe(us->pusb_dev,0), + us->recv_ctrl_pipe, 0x02, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, 0x0000, diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c --- a/drivers/usb/storage/jumpshot.c Tue Oct 15 20:29:11 2002 +++ b/drivers/usb/storage/jumpshot.c Tue Oct 15 20:29:11 2002 @@ -62,13 +62,12 @@ unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("jumpshot_bulk_read: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_READ, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, len, NULL); } @@ -76,13 +75,12 @@ unsigned char *data, unsigned int len) { - unsigned int act_len; /* ignored */ - if (len == 0) return USB_STOR_XFER_GOOD; US_DEBUGP("jumpshot_bulk_write: len = %d\n", len); - return usb_storage_raw_bulk(us, SCSI_DATA_WRITE, data, len, &act_len); + return usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, + data, len, NULL); } @@ -95,12 +93,11 @@ return USB_STOR_TRANSPORT_ERROR; // send the setup - rc = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev, 0), + rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, 0, 0xA0, 0, 7, &reply, 1); - if (rc != USB_STOR_TRANSPORT_GOOD) - return rc; + if (rc != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (reply != 0x50) { US_DEBUGP("jumpshot_get_status: 0x%2x\n", @@ -160,10 +157,9 @@ command[5] |= (sector >> 24) & 0x0F; // send the setup + command - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 1, command, 7); - if (result != USB_STOR_TRANSPORT_GOOD) + if (result != USB_STOR_XFER_GOOD) goto leave; // read the result @@ -247,9 +243,10 @@ command[5] |= (sector >> 24) & 0x0F; // send the setup + command - result = usb_storage_send_control( - us, usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 1, command, 7); + if (result != USB_STOR_XFER_GOOD) + goto leave; // send the data result = jumpshot_bulk_write(us, ptr, len); @@ -302,11 +299,10 @@ return USB_STOR_TRANSPORT_ERROR; // send the setup - rc = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev, 0), + rc = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, 0, 0x20, 0, 6, command, 2); - if (rc != USB_STOR_TRANSPORT_GOOD) { + if (rc != USB_STOR_XFER_GOOD) { US_DEBUGP("jumpshot_id_device: Gah! " "send_control for read_capacity failed\n"); return rc; @@ -468,7 +464,7 @@ 0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00 }; - + srb->resid = 0; if (!us->extra) { us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO); if (!us->extra) { diff -Nru a/drivers/usb/storage/raw_bulk.c b/drivers/usb/storage/raw_bulk.c --- a/drivers/usb/storage/raw_bulk.c Tue Oct 15 20:29:19 2002 +++ b/drivers/usb/storage/raw_bulk.c Tue Oct 15 20:29:19 2002 @@ -13,219 +13,6 @@ #include "transport.h" #include "raw_bulk.h" -#ifdef CONFIG_USB_STORAGE_DEBUG -#define DEBUG_PRCT 12 -#else -#define DEBUG_PRCT 0 -#endif - -/* - * Send a control message and wait for the response. - * - * us - the pointer to the us_data structure for the device to use - * - * request - the URB Setup Packet's first 6 bytes. The first byte always - * corresponds to the request type, and the second byte always corresponds - * to the request. The other 4 bytes do not correspond to value and index, - * since they are used in a custom way by the SCM protocol. - * - * xfer_data - a buffer from which to get, or to which to store, any data - * that gets send or received, respectively, with the URB. Even though - * it looks like we allocate a buffer in this code for the data, xfer_data - * must contain enough allocated space. - * - * xfer_len - the number of bytes to send or receive with the URB. - * - */ - -int -usb_storage_send_control(struct us_data *us, - int pipe, - unsigned char request, - unsigned char requesttype, - unsigned int value, - unsigned int index, - unsigned char *xfer_data, - unsigned int xfer_len) { - - int result; - - // Send the URB to the device and wait for a response. - - /* Why are request and request type reversed in this call? */ - - result = usb_stor_control_msg(us, pipe, - request, requesttype, value, index, - xfer_data, xfer_len); - - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_send_control(): transfer aborted\n"); - return USB_STOR_TRANSPORT_ABORTED; - } - - // Check the return code for the command. - if (result < 0) { - - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - /* Uh oh... serious problem here */ - return USB_STOR_TRANSPORT_ERROR; - } - - return USB_STOR_TRANSPORT_GOOD; -} - -int -usb_storage_raw_bulk(struct us_data *us, int direction, unsigned char *data, - unsigned int len, unsigned int *act_len) { - - int result; - int pipe; - - if (direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - result = usb_stor_bulk_msg(us, data, pipe, len, act_len); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("EPIPE: clearing endpoint halt for" - " pipe 0x%x, stalled at %d bytes\n", - pipe, *act_len); - if (usb_stor_clear_halt(us, pipe) < 0) - return USB_STOR_XFER_ERROR; - return USB_STOR_XFER_STALLED; - } - - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_storage_raw_bulk(): transfer aborted\n"); - return USB_STOR_XFER_ABORTED; - } - - if (result) { - /* NAK - that means we've retried a few times already */ - if (result == -ETIMEDOUT) - US_DEBUGP("raw_bulk(): device NAKed\n"); - else if (result == -EOVERFLOW) - US_DEBUGP("raw_bulk(): babble/overflow\n"); - else if (result == -ECONNRESET) - US_DEBUGP("raw_bulk(): asynchronous reset\n"); - else if (result != -EPIPE) - US_DEBUGP("raw_bulk(): unknown error %d\n", - result); - - return USB_STOR_XFER_ERROR; - } - - if (*act_len != len) { - US_DEBUGP("Warning: Transferred only %d of %d bytes\n", - *act_len, len); - return USB_STOR_XFER_SHORT; - } - -#if 0 - US_DEBUGP("raw_bulk(): Transferred %s %d of %d bytes\n", - (direction == SCSI_DATA_READ) ? "in" : "out", - *act_len, len); -#endif - - return USB_STOR_XFER_GOOD; -} - -int -usb_storage_bulk_transport(struct us_data *us, int direction, - unsigned char *data, unsigned int len, - int use_sg) { - - int result = USB_STOR_XFER_ERROR; - int transferred = 0; - int i; - struct scatterlist *sg; - unsigned int act_len; - - if (len == 0) - return USB_STOR_XFER_GOOD; - -#if DEBUG_PRCT - - if (direction == SCSI_DATA_WRITE && !use_sg) { - char string[64]; - - /* Debug-print the first N bytes of the write transfer */ - - strcpy(string, "wr: "); - for (i=0; i sg[i].length) - length = sg[i].length; - - result = usb_storage_raw_bulk(us, direction, - buf, length, &act_len); - if (result != USB_STOR_XFER_GOOD) - break; - transferred += length; - } - } - -#if DEBUG_PRCT - - if (direction == SCSI_DATA_READ && !use_sg) { - char string[64]; - - /* Debug-print the first N bytes of the read transfer */ - - strcpy(string, "rd: "); - for (i=0; ipusb_dev,0); + pipe = us->recv_ctrl_pipe; else - pipe = usb_sndctrlpipe(us->pusb_dev,0); + pipe = us->send_ctrl_pipe; - return usb_storage_send_control(us, pipe, request, requesttype, + rc = usb_stor_ctrl_transfer(us, pipe, request, requesttype, 0, 0, xfer_data, xfer_len); + return (rc == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : + USB_STOR_TRANSPORT_ERROR); } static int @@ -276,7 +279,6 @@ 0x03, LUNBITS, 0, 0, buflen, 0, 0, 0, 0, 0, 0, 0 }; int result; - unsigned int act_len; result = sddr09_send_scsi_command(us, command, sizeof(command)); if (result != USB_STOR_TRANSPORT_GOOD) { @@ -284,7 +286,8 @@ return result; } - result = usb_storage_raw_bulk(us, SCSI_DATA_READ, sensebuf, buflen, &act_len); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + sensebuf, buflen, NULL); if (result != USB_STOR_XFER_GOOD) { US_DEBUGP("request sense bulk in failed\n"); return USB_STOR_TRANSPORT_ERROR; @@ -343,11 +346,11 @@ return result; } - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - buf, bulklen, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, + buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_read2%d %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_read2%d %d\n", x, result); return USB_STOR_TRANSPORT_ERROR; } @@ -510,11 +513,11 @@ return result; } - result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, - buf, bulklen, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, + buf, bulklen, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_writeX %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_writeX %d\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -592,11 +595,11 @@ if (!buf) return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - buf, bulklen, 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + buf, bulklen, NULL); kfree(buf); if (result != USB_STOR_XFER_GOOD) { - US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n", + US_DEBUGP("Result for bulk_transfer in sddr09_read_sg %d\n", result); return USB_STOR_TRANSPORT_ERROR; } @@ -631,8 +634,8 @@ if (result != USB_STOR_TRANSPORT_GOOD) return result; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, - data, sizeof(data), 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + data, sizeof(data), NULL); *status = data[0]; return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -954,7 +957,8 @@ if (result != USB_STOR_TRANSPORT_GOOD) return result; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, 64, 0); + result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, + content, 64, NULL); for (i = 0; i < 4; i++) deviceID[i] = content[i]; @@ -1368,6 +1372,7 @@ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + srb->resid = 0; info = (struct sddr09_card_info *)us->extra; if (!info) { nand_init_ecc(); @@ -1544,17 +1549,16 @@ if (srb->sc_data_direction == SCSI_DATA_WRITE || srb->sc_data_direction == SCSI_DATA_READ) { + unsigned int pipe = (srb->sc_data_direction == SCSI_DATA_WRITE) + ? us->send_bulk_pipe : us->recv_bulk_pipe; US_DEBUGP("SDDR09: %s %d bytes\n", (srb->sc_data_direction == SCSI_DATA_WRITE) ? "sending" : "receiving", srb->request_bufflen); - result = usb_storage_bulk_transport(us, - srb->sc_data_direction, - srb->request_buffer, - srb->request_bufflen, - srb->use_sg); + result = usb_stor_bulk_transfer_srb(us, pipe, srb, + srb->request_bufflen); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); diff -Nru a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c --- a/drivers/usb/storage/sddr55.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/storage/sddr55.c Tue Oct 15 20:29:16 2002 @@ -75,10 +75,13 @@ sddr55_bulk_transport(struct us_data *us, int direction, unsigned char *data, unsigned int len) { struct sddr55_card_info *info = (struct sddr55_card_info *)us->extra; + unsigned int pipe = (direction == SCSI_DATA_READ) ? + us->recv_bulk_pipe : us->send_bulk_pipe; - if (len) - info->last_access = jiffies; - return usb_storage_bulk_transport(us, direction, data, len, 0); + if (!len) + return USB_STOR_XFER_GOOD; + info->last_access = jiffies; + return usb_stor_bulk_transfer_buf(us, pipe, data, len, NULL); } /* check if card inserted, if there is, update read_only status @@ -743,6 +746,7 @@ unsigned short pages; struct sddr55_card_info *info; + srb->resid = 0; if (!us->extra) { us->extra = kmalloc( sizeof(struct sddr55_card_info), GFP_NOIO); diff -Nru a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c --- a/drivers/usb/storage/shuttle_usbat.c Tue Oct 15 20:29:11 2002 +++ b/drivers/usb/storage/shuttle_usbat.c Tue Oct 15 20:29:11 2002 @@ -50,12 +50,6 @@ #include #include -extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); - #define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) @@ -69,8 +63,8 @@ int result; - result = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->recv_ctrl_pipe, access, 0xC0, (u16)reg, @@ -88,8 +82,8 @@ int result; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, access|0x01, 0x40, short_pack(reg, content), @@ -114,8 +108,8 @@ test_pattern, mask_byte, subcountL, subcountH }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -139,8 +133,11 @@ LSB_of(len), MSB_of(len) }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + if (!len) + return USB_STOR_TRANSPORT_GOOD; + + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -148,10 +145,11 @@ command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_READ, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->recv_bulk_pipe, + content, len, use_sg, NULL); return (result == USB_STOR_XFER_GOOD ? USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR); @@ -178,8 +176,8 @@ result = usbat_read(us, USBAT_ATA, 0x17, &status); - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; + if (result!=USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (status&0x01) { // check condition result = usbat_read(us, USBAT_ATA, 0x10, &status); return USB_STOR_TRANSPORT_FAILED; @@ -221,8 +219,11 @@ LSB_of(len), MSB_of(len) }; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + if (!len) + return USB_STOR_TRANSPORT_GOOD; + + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -230,10 +231,11 @@ command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, SCSI_DATA_WRITE, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, us->send_bulk_pipe, + content, len, use_sg, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -257,6 +259,8 @@ int minutes) { int result; + unsigned int pipe = (direction == SCSI_DATA_READ) ? + us->recv_bulk_pipe : us->send_bulk_pipe; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, // but that's what came out of the trace every single time. @@ -292,8 +296,8 @@ * that, we just return a failure. */ - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -301,16 +305,16 @@ (i==0 ? command : command+8), (i==0 ? 16 : 8)); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (i==0) { - result = usb_storage_bulk_transport(us, - SCSI_DATA_WRITE, - data, num_registers*2, 0); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, + data, num_registers*2, NULL); - if (result!=USB_STOR_XFER_GOOD) + if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; } @@ -320,8 +324,8 @@ // direction == SCSI_DATA_WRITE ? "out" : "in", // len, use_sg); - result = usb_storage_bulk_transport(us, - direction, content, len, use_sg); + result = usb_stor_bulk_transfer_sg(us, + pipe, content, len, use_sg, NULL); /* * If we get a stall on the bulk download, we'll retry @@ -352,8 +356,7 @@ if (direction==SCSI_DATA_READ && i==0) { if (usb_stor_clear_halt(us, - usb_sndbulkpipe(us->pusb_dev, - us->ep_out)) < 0) + us->send_bulk_pipe) < 0) return USB_STOR_TRANSPORT_ERROR; } @@ -365,8 +368,8 @@ direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, &status); - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; + if (result!=USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; if (status&0x01) // check condition return USB_STOR_TRANSPORT_FAILED; if (status&0x20) // device fault @@ -412,8 +415,8 @@ data[1+(i<<1)] = data_out[i]; } - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x80, 0x40, 0, @@ -421,11 +424,11 @@ command, 8); - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + if (result != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; - result = usb_storage_bulk_transport(us, - SCSI_DATA_WRITE, data, num_registers*2, 0); + result = usb_stor_bulk_transfer_buf(us, + us->send_bulk_pipe, data, num_registers*2, NULL); if (result != USB_STOR_XFER_GOOD) return USB_STOR_TRANSPORT_ERROR; @@ -438,8 +441,8 @@ int result; - result = usb_storage_send_control(us, - usb_rcvctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->recv_ctrl_pipe, 0x82, 0xC0, 0, @@ -456,8 +459,8 @@ int result; - result = usb_storage_send_control(us, - usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, + us->send_ctrl_pipe, 0x82, 0x40, short_pack(enable_flags, data_flags), @@ -589,7 +592,6 @@ static int hp_8200e_select_and_test_registers(struct us_data *us) { - int result; int selector; unsigned char status; @@ -597,44 +599,44 @@ for (selector = 0xA0; selector <= 0xB0; selector += 0x10) { - if ( (result = usbat_write(us, USBAT_ATA, 0x16, selector)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x17, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x16, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_write(us, USBAT_ATA, 0x14, 0x55)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_write(us, USBAT_ATA, 0x15, 0xAA)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; - - if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ATA, 0x16, selector) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_read(us, USBAT_ATA, 0x17, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_read(us, USBAT_ATA, 0x16, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_write(us, USBAT_ATA, 0x14, 0x55) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_write(us, USBAT_ATA, 0x15, 0xAA) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; + + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; } - return result; + return USB_STOR_TRANSPORT_GOOD; } int init_8200e(struct us_data *us) { @@ -644,44 +646,44 @@ // Enable peripheral control signals - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 1\n"); wait_ms(2000); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 2\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 3\n"); // Reset peripheral, enable periph control signals // (bring reset signal up) - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 4\n"); // Enable periph control signals // (bring reset signal down) - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 5\n"); @@ -689,23 +691,23 @@ // Write 0x80 to ISA port 0x3F - if ( (result = usbat_write(us, USBAT_ISA, 0x3F, 0x80)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_write(us, USBAT_ISA, 0x3F, 0x80) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 6\n"); // Read ISA port 0x27 - if ( (result = usbat_read(us, USBAT_ISA, 0x27, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read(us, USBAT_ISA, 0x27, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 7\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 8\n"); @@ -715,32 +717,32 @@ US_DEBUGP("INIT 9\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 10\n"); // Enable periph control signals and card detect - if ( (result = usbat_write_user_io(us, + if (usbat_write_user_io(us, USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0, - USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD) - return result; + USBAT_UIO_EPAD | USBAT_UIO_1) != USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 11\n"); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 12\n"); wait_ms(1400); - if ( (result = usbat_read_user_io(us, &status)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_read_user_io(us, &status) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 13\n"); @@ -750,14 +752,14 @@ US_DEBUGP("INIT 14\n"); - if ( (result = usbat_set_shuttle_features(us, - 0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) != - USB_STOR_TRANSPORT_GOOD) - return result; + if (usbat_set_shuttle_features(us, + 0x83, 0x00, 0x88, 0x08, 0x15, 0x14) != + USB_STOR_XFER_GOOD) + return USB_STOR_TRANSPORT_ERROR; US_DEBUGP("INIT 15\n"); - return result; + return USB_STOR_TRANSPORT_ERROR; } /* @@ -773,6 +775,7 @@ int i; char string[64]; + srb->resid = 0; len = srb->request_bufflen; /* Send A0 (ATA PACKET COMMAND). @@ -863,17 +866,16 @@ // How many bytes to read in? Check cylL register - if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; + if (usbat_read(us, USBAT_ATA, 0x14, &status) != + USB_STOR_XFER_GOOD) { + return USB_STOR_TRANSPORT_ERROR; } - if (len>0xFF) { // need to read cylH also + if (len > 0xFF) { // need to read cylH also len = status; - if ( (result = usbat_read(us, USBAT_ATA, 0x15, - &status)) != - USB_STOR_TRANSPORT_GOOD) { - return result; + if (usbat_read(us, USBAT_ATA, 0x15, &status) != + USB_STOR_XFER_GOOD) { + return USB_STOR_TRANSPORT_ERROR; } len += ((unsigned int)status)<<8; } diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/storage/transport.c Tue Oct 15 20:29:16 2002 @@ -488,7 +488,7 @@ /* This is our function to emulate usb_bulk_msg() with enough control * to make aborts/resets/timeouts work */ -int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, +int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe, unsigned int len, unsigned int *act_len) { int status; @@ -515,13 +515,12 @@ * Since many vendors in this space limit their testing to interoperability * with these two OSes, specification violations like this one are common. */ -int usb_stor_clear_halt(struct us_data *us, int pipe) +int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) { int result; int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7); - result = usb_stor_control_msg(us, - usb_sndctrlpipe(us->pusb_dev, 0), + result = usb_stor_control_msg(us, us->send_ctrl_pipe, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, endp, NULL, 0); /* note: no 3*HZ timeout */ US_DEBUGP("usb_stor_clear_halt: result=%d\n", result); @@ -542,37 +541,81 @@ } /* - * Transfer one SCSI scatter-gather buffer via bulk transfer + * Transfer one control message * - * Note that this function is necessary because we want the ability to - * use scatter-gather memory. Good performance is achieved by a combination - * of scatter-gather and clustering (which makes each chunk bigger). + * This function does basically the same thing as usb_stor_control_msg() + * above, except that return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. + */ +int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size) { + int result; + + US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x " + "value=%04x index=%02x len=%d\n", + request, requesttype, value, index, size); + result = usb_stor_control_msg(us, pipe, request, requesttype, + value, index, data, size); + US_DEBUGP("usb_stor_control_msg returned %d\n", result); + + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("-- transfer aborted\n"); + return USB_STOR_XFER_ABORTED; + } + + /* a stall indicates a protocol error */ + if (result == -EPIPE) { + US_DEBUGP("-- stall on control pipe\n"); + return USB_STOR_XFER_ERROR; + } + + /* some other serious problem here */ + if (result < 0) { + US_DEBUGP("-- unknown error\n"); + return USB_STOR_XFER_ERROR; + } + + /* was the entire command transferred? */ + if (result < size) { + US_DEBUGP("-- transferred only %d bytes\n", result); + return USB_STOR_XFER_SHORT; + } + + US_DEBUGP("-- transfer completed successfully\n"); + return USB_STOR_XFER_GOOD; +} + +/* + * Transfer one buffer via bulk transfer + * + * This function does basically the same thing as usb_stor_bulk_msg() + * above, except that: * - * Note that the lower layer will always retry when a NAK occurs, up to the - * timeout limit. Thus we don't have to worry about it for individual - * packets. + * 1. If the bulk pipe stalls during the transfer, the halt is + * automatically cleared; + * 2. Return codes are USB_STOR_XFER_xxx rather than the + * urb status or transfer length. */ -int usb_stor_transfer_partial(struct us_data *us, char *buf, int length) +int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len) { int result; int partial; - int pipe; - - /* calculate the appropriate pipe information */ - if (us->srb->sc_data_direction == SCSI_DATA_READ) - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - else - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); /* transfer the data */ - US_DEBUGP("usb_stor_transfer_partial(): xfer %d bytes\n", length); + US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %d bytes\n", length); result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n", result, partial, length); + if (act_len) + *act_len = partial; /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x," + " stalled at %d bytes\n", pipe, partial); if (usb_stor_clear_halt(us, pipe) < 0) return USB_STOR_XFER_ERROR; return USB_STOR_XFER_STALLED; @@ -580,25 +623,25 @@ /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_transfer_partial(): transfer aborted\n"); + US_DEBUGP("-- transfer aborted\n"); return USB_STOR_XFER_ABORTED; } /* NAK - that means we've retried a few times already */ if (result == -ETIMEDOUT) { - US_DEBUGP("usb_stor_transfer_partial(): device NAKed\n"); + US_DEBUGP("-- device NAKed\n"); return USB_STOR_XFER_ERROR; } /* the catch-all error case */ if (result) { - US_DEBUGP("usb_stor_transfer_partial(): unknown error\n"); + US_DEBUGP("-- unknown error\n"); return USB_STOR_XFER_ERROR; } /* did we send all the data? */ if (partial == length) { - US_DEBUGP("usb_stor_transfer_partial(): transfer complete\n"); + US_DEBUGP("-- transfer complete\n"); return USB_STOR_XFER_GOOD; } @@ -611,59 +654,51 @@ * Transfer an entire SCSI command's worth of data payload over the bulk * pipe. * - * Note that this uses usb_stor_transfer_partial to achieve its goals -- this + * Note that this uses usb_stor_transfer_buf to achieve its goals -- this * function simply determines if we're going to use scatter-gather or not, * and acts appropriately. For now, it also re-interprets the error codes. */ -void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us) +int usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe, + char *buf, unsigned int length_left, int use_sg, int *residual) { int i; int result = -1; struct scatterlist *sg; - unsigned int total_transferred = 0; - unsigned int transfer_amount; - - /* calculate how much we want to transfer */ - transfer_amount = usb_stor_transfer_length(srb); - - /* was someone foolish enough to request more data than available - * buffer space? */ - if (transfer_amount > srb->request_bufflen) - transfer_amount = srb->request_bufflen; + unsigned int amount; + unsigned int partial; /* are we scatter-gathering? */ - if (srb->use_sg) { + if (use_sg) { /* loop over all the scatter gather structures and * make the appropriate requests for each, until done */ - sg = (struct scatterlist *) srb->request_buffer; - for (i = 0; i < srb->use_sg; i++) { + sg = (struct scatterlist *) buf; + for (i = 0; (i < use_sg) && (length_left > 0); (i++, ++sg)) { /* transfer the lesser of the next buffer or the * remaining data */ - if (transfer_amount - total_transferred >= - sg[i].length) { - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), sg[i].length); - total_transferred += sg[i].length; - } else - result = usb_stor_transfer_partial(us, - sg_address(sg[i]), - transfer_amount - total_transferred); + amount = sg->length < length_left ? + sg->length : length_left; + result = usb_stor_bulk_transfer_buf(us, pipe, + sg_address(*sg), amount, &partial); + length_left -= partial; /* if we get an error, end the loop here */ - if (result) + if (result != USB_STOR_XFER_GOOD) break; } - } - else + } else { /* no scatter-gather, just make the request */ - result = usb_stor_transfer_partial(us, srb->request_buffer, - transfer_amount); + result = usb_stor_bulk_transfer_buf(us, pipe, buf, + length_left, &partial); + length_left -= partial; + } - /* return the result in the data structure itself */ - srb->result = result; + /* store the residual and return the error code */ + if (residual) + *residual = length_left; + return result; } /*********************************************************************** @@ -742,7 +777,7 @@ * Also, if we have a short transfer on a command that can't have * a short transfer, we're going to do this. */ - if ((srb->result == USB_STOR_XFER_SHORT) && + if ((srb->resid > 0) && !((srb->cmnd[0] == REQUEST_SENSE) || (srb->cmnd[0] == INQUIRY) || (srb->cmnd[0] == MODE_SENSE) || @@ -974,6 +1009,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* re-initialize the mutex so that we avoid any races with @@ -985,14 +1021,14 @@ /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); + if (result != USB_STOR_XFER_GOOD) { /* Reset flag for status notification */ clear_bit(US_FLIDX_IP_WANTED, &us->flags); } @@ -1003,22 +1039,16 @@ return USB_STOR_TRANSPORT_ABORTED; } - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } - - if (result < 0) { + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length > 0) { + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CBI data stage result is 0x%x\n", result); /* report any errors */ @@ -1093,39 +1123,34 @@ */ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) { + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; /* COMMAND STAGE */ /* let's send the command via the control pipe */ - result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_stor_ctrl_transfer(us, us->send_ctrl_pipe, US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, srb->cmnd, srb->cmd_len); /* check the return code for the command */ - US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); - if (result < 0) { - /* did we abort this command? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { - US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); - return USB_STOR_TRANSPORT_ABORTED; - } + US_DEBUGP("Call to usb_stor_ctrl_transfer() returned %d\n", result); - /* a stall indicates a protocol error */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe\n"); - return USB_STOR_TRANSPORT_ERROR; - } + /* did we abort this command? */ + if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + US_DEBUGP("usb_stor_CB_transport(): transfer aborted\n"); + return USB_STOR_TRANSPORT_ABORTED; + if (result != USB_STOR_XFER_GOOD) { /* Uh oh... serious problem here */ return USB_STOR_TRANSPORT_ERROR; } /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ - if (usb_stor_transfer_length(srb)) { - usb_stor_transfer(srb, us); - result = srb->result; + if (transfer_length) + result = usb_stor_bulk_transfer_srb(us, us->send_bulk_pipe, + srb, transfer_length); US_DEBUGP("CB data stage result is 0x%x\n", result); /* report any errors */ @@ -1153,12 +1178,12 @@ { unsigned char data; int result; - int pipe; - /* issue the command -- use usb_control_msg() because - * this is not a scsi queued-command */ - pipe = usb_rcvctrlpipe(us->pusb_dev, 0); - result = usb_control_msg(us->pusb_dev, pipe, + /* Issue the command -- use usb_control_msg() because this is + * not a scsi queued-command. Also note that at this point the + * cached pipe values have not yet been stored. */ + result = usb_control_msg(us->pusb_dev, + usb_rcvctrlpipe(us->pusb_dev, 0), US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, @@ -1179,13 +1204,13 @@ { struct bulk_cb_wrap bcb; struct bulk_cs_wrap bcs; + unsigned int transfer_length = usb_stor_transfer_length(srb); int result; - int pipe; int partial; /* set up the command wrapper */ bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); - bcb.DataTransferLength = cpu_to_le32(usb_stor_transfer_length(srb)); + bcb.DataTransferLength = cpu_to_le32(transfer_length); bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb.Tag = srb->serial_number; bcb.Lun = srb->cmnd[1] >> 5; @@ -1193,9 +1218,6 @@ bcb.Lun |= srb->target << 4; bcb.Length = srb->cmd_len; - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - /* copy the command payload */ memset(bcb.CDB, 0, sizeof(bcb.CDB)); memcpy(bcb.CDB, srb->cmnd, bcb.Length); @@ -1205,8 +1227,8 @@ le32_to_cpu(bcb.Signature), bcb.Tag, (bcb.Lun >> 4), (bcb.Lun & 0x0F), bcb.DataTransferLength, bcb.Flags, bcb.Length); - result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe, + US_BULK_CB_WRAP_LEN, &partial); US_DEBUGP("Bulk command transfer result=%d\n", result); /* did we abort this command? */ @@ -1217,47 +1239,45 @@ /* if we stall, we need to clear it before we go on */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->send_bulk_pipe); + result = usb_stor_clear_halt(us, us->send_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n"); return USB_STOR_TRANSPORT_ABORTED; } - if (result < 0) - return USB_STOR_TRANSPORT_ERROR; - result = -EPIPE; + return USB_STOR_TRANSPORT_ERROR; } else if (result) { /* unknown error -- we've got a problem */ return USB_STOR_TRANSPORT_ERROR; } - /* if the command transfered well, then we go to the data stage */ - if (result == 0) { - /* send/receive data payload, if there is any */ - if (bcb.DataTransferLength) { - usb_stor_transfer(srb, us); - result = srb->result; - US_DEBUGP("Bulk data transfer result 0x%x\n", result); + /* DATA STAGE */ + /* send/receive data payload, if there is any */ + if (transfer_length) { + unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? + us->recv_bulk_pipe : us->send_bulk_pipe; + result = usb_stor_bulk_transfer_srb(us, pipe, srb, + transfer_length); + US_DEBUGP("Bulk data transfer result 0x%x\n", result); - /* if it was aborted, we need to indicate that */ - if (result == USB_STOR_XFER_ABORTED) - return USB_STOR_TRANSPORT_ABORTED; - } + /* if it was aborted, we need to indicate that */ + if (result == USB_STOR_XFER_ABORTED) + return USB_STOR_TRANSPORT_ABORTED; + if (result == USB_STOR_XFER_ERROR) + return USB_STOR_TRANSPORT_ERROR; } /* See flow chart on pg 15 of the Bulk Only Transport spec for * an explanation of how this code works. */ - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - /* get CSW for device status */ US_DEBUGP("Attempting to get CSW...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, - &partial); + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, + US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1267,8 +1287,9 @@ /* did the attempt to read the CSW fail? */ if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", + us->recv_bulk_pipe); + result = usb_stor_clear_halt(us, us->recv_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1280,7 +1301,7 @@ /* get the status again */ US_DEBUGP("Attempting to get CSW (2nd try)...\n"); - result = usb_stor_bulk_msg(us, &bcs, pipe, + result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe, US_BULK_CS_WRAP_LEN, &partial); /* did we abort this command? */ @@ -1291,8 +1312,9 @@ /* if it fails again, we need a reset and return an error*/ if (result == -EPIPE) { - US_DEBUGP("clearing halt for pipe 0x%x\n", pipe); - result = usb_stor_clear_halt(us, pipe); + US_DEBUGP("clearing halt for pipe 0x%x\n", + us->recv_bulk_pipe); + result = usb_stor_clear_halt(us, us->recv_bulk_pipe); /* did we abort this command? */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { @@ -1364,7 +1386,7 @@ * following a powerup or USB attach event. */ /* Use usb_control_msg() because this is not a queued-command */ - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, request, requesttype, value, index, data, size, 20*HZ); if (result < 0) @@ -1377,14 +1399,12 @@ /* Use usb_clear_halt() because this is not a queued-command */ US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, - usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + result = usb_clear_halt(us->pusb_dev, us->recv_bulk_pipe); if (result < 0) goto Done; US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, - usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + result = usb_clear_halt(us->pusb_dev, us->send_bulk_pipe); Done: diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Tue Oct 15 20:29:16 2002 +++ b/drivers/usb/storage/transport.h Tue Oct 15 20:29:16 2002 @@ -115,7 +115,7 @@ #define US_BULK_GET_MAX_LUN 0xfe /* - * usb_stor_transfer() return codes, in order of severity + * usb_stor_bulk_transfer_xxx() return codes, in order of severity */ #define USB_STOR_XFER_GOOD 0 /* good transfer */ #define USB_STOR_XFER_SHORT 1 /* transfered less than expected */ @@ -151,14 +151,26 @@ extern unsigned int usb_stor_transfer_length(Scsi_Cmnd*); extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); extern void usb_stor_abort_transport(struct us_data*); -extern int usb_stor_transfer_partial(struct us_data*, char*, int); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, - unsigned int len, unsigned int *act_len); +extern int usb_stor_bulk_msg(struct us_data *us, void *data, + unsigned int pipe, unsigned int len, unsigned int *act_len); extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size); -extern int usb_stor_clear_halt(struct us_data*, int ); -extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*); +extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe); +extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size); +extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, unsigned int *act_len); +extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe, + char *buf, unsigned int length, int use_sg, int *residual); + +static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us, + unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) { + return usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer, + length, srb->use_sg, &srb->resid); +} + #endif diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Tue Oct 15 20:29:14 2002 +++ b/drivers/usb/storage/usb.c Tue Oct 15 20:29:14 2002 @@ -525,6 +525,12 @@ int maxp; int result; + /* calculate and store the pipe values */ + ss->send_bulk_pipe = usb_sndbulkpipe(ss->pusb_dev, ss->ep_out); + ss->recv_bulk_pipe = usb_rcvbulkpipe(ss->pusb_dev, ss->ep_in); + ss->send_ctrl_pipe = usb_sndctrlpipe(ss->pusb_dev, 0); + ss->recv_ctrl_pipe = usb_rcvctrlpipe(ss->pusb_dev, 0); + /* allocate the usb_ctrlrequest for control packets */ US_DEBUGP("Allocating usb_ctrlrequest\n"); ss->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h Tue Oct 15 20:29:17 2002 +++ b/drivers/usb/storage/usb.h Tue Oct 15 20:29:17 2002 @@ -134,6 +134,10 @@ struct semaphore dev_semaphore; /* protect pusb_dev */ struct usb_device *pusb_dev; /* this usb_device */ unsigned long flags; /* from filter initially */ + unsigned int send_bulk_pipe; /* cached pipe values */ + unsigned int recv_bulk_pipe; + unsigned int send_ctrl_pipe; + unsigned int recv_ctrl_pipe; /* information about the device -- always good */ char vendor[USB_STOR_STRING_LEN]; diff -Nru a/drivers/video/acornfb.c b/drivers/video/acornfb.c --- a/drivers/video/acornfb.c Tue Oct 15 20:29:16 2002 +++ b/drivers/video/acornfb.c Tue Oct 15 20:29:16 2002 @@ -380,7 +380,7 @@ * vder : >= vdsr */ static void -acornfb_set_timing(struct fb_var_screeninfo *var) +acornfb_set_timing(struct fb_info *info, struct fb_var_screeninfo *var) { struct vidc_timing vidc; u_int vcr, fsize; @@ -470,7 +470,7 @@ words_per_line = var->xres * var->bits_per_pixel / 32; - if (current_par.using_vram && current_par.screen_size == 2048*1024) + if (current_par.using_vram && info->fix.smem_len == 2048*1024) words_per_line /= 2; /* RiscPC doesn't use the VIDC's VRAM control. */ @@ -549,7 +549,7 @@ * the resolution to fit the rules. */ static int -acornfb_adjust_timing(struct fb_var_screeninfo *var, int con) +acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, int con) { u_int font_line_len; u_int fontht; @@ -595,13 +595,13 @@ * If minimum screen size is greater than that we have * available, reject it. */ - if (min_size > current_par.screen_size) + if (min_size > info->fix.smem_len) return -EINVAL; /* Find int 'y', such that y * fll == s * sam < maxsize * y = s * sam / fll; s = maxsize / sam */ - for (size = current_par.screen_size; + for (size = info->fix.smem_len; nr_y = size / font_line_len, min_size <= size; size -= sam_size) { if (nr_y * font_line_len == size) @@ -614,14 +614,14 @@ /* * failed, use ypan */ - size = current_par.screen_size; + size = info->fix.smem_len; var->yres_virtual = size / (font_line_len / fontht); } else var->yres_virtual = nr_y; } else if (var->yres_virtual > nr_y) var->yres_virtual = nr_y; - current_par.screen_end = current_par.screen_base_p + size; + current_par.screen_end = info->fix.smem_start + size; /* * Fix yres & yoffset if needed. @@ -691,7 +691,7 @@ } static inline void -acornfb_update_dma(struct fb_var_screeninfo *var) +acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var) { int off = (var->yoffset * var->xres_virtual * var->bits_per_pixel) >> 3; @@ -699,7 +699,7 @@ #if defined(HAS_MEMC) memc_write(VDMA_INIT, off >> 2); #elif defined(HAS_IOMD) - iomd_writel(current_par.screen_base_p + off, IOMD_VIDINIT); + iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT); #endif } @@ -792,7 +792,7 @@ } static int -acornfb_decode_var(struct fb_var_screeninfo *var, int con) +acornfb_decode_var(struct fb_info *info, struct fb_var_screeninfo *var, int con) { int err; @@ -865,7 +865,7 @@ * Validate and adjust the resolution to * match the video generator hardware. */ - err = acornfb_adjust_timing(var, con); + err = acornfb_adjust_timing(info, var, con); if (err) return err; @@ -877,55 +877,18 @@ } static int -acornfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) -{ - struct display *display; - - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "Acorn"); - - if (con >= 0) - display = fb_display + con; - else - display = &global_disp; - - fix->smem_start = current_par.screen_base_p; - fix->smem_len = current_par.screen_size; - fix->type = display->type; - fix->type_aux = display->type_aux; - fix->xpanstep = 0; - fix->ypanstep = display->ypanstep; - fix->ywrapstep = display->ywrapstep; - fix->visual = display->visual; - fix->line_length = display->line_length; - fix->accel = FB_ACCEL_NONE; - - return 0; -} - -static int -acornfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) -{ - if (con == -1) { - *var = global_disp.var; - } else - *var = fb_display[con].var; - - return 0; -} - -static int acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) { struct display *display; - int err, chgvar = 0; + unsigned int visual, chgvar = 0; + int err; if (con >= 0) display = fb_display + con; else display = &global_disp; - err = acornfb_decode_var(var, con); + err = acornfb_decode_var(info, var, con); if (err) return err; @@ -969,21 +932,21 @@ case 1: current_par.palette_size = 2; display->dispsw = &fbcon_mfb; - display->visual = FB_VISUAL_MONO10; + visual = FB_VISUAL_MONO10; break; #endif #ifdef FBCON_HAS_CFB2 case 2: current_par.palette_size = 4; display->dispsw = &fbcon_cfb2; - display->visual = FB_VISUAL_PSEUDOCOLOR; + visual = FB_VISUAL_PSEUDOCOLOR; break; #endif #ifdef FBCON_HAS_CFB4 case 4: current_par.palette_size = 16; display->dispsw = &fbcon_cfb4; - display->visual = FB_VISUAL_PSEUDOCOLOR; + visual = FB_VISUAL_PSEUDOCOLOR; break; #endif #ifdef FBCON_HAS_CFB8 @@ -991,9 +954,9 @@ current_par.palette_size = VIDC_PALETTE_SIZE; display->dispsw = &fbcon_cfb8; #ifdef HAS_VIDC - display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR; + visual = FB_VISUAL_STATIC_PSEUDOCOLOR; #else - display->visual = FB_VISUAL_PSEUDOCOLOR; + visual = FB_VISUAL_PSEUDOCOLOR; #endif break; #endif @@ -1002,7 +965,7 @@ current_par.palette_size = 32; display->dispsw = &fbcon_cfb16; display->dispsw_data = current_par.cmap.cfb16; - display->visual = FB_VISUAL_DIRECTCOLOR; + visual = FB_VISUAL_DIRECTCOLOR; break; #endif #ifdef FBCON_HAS_CFB32 @@ -1010,22 +973,17 @@ current_par.palette_size = VIDC_PALETTE_SIZE; display->dispsw = &fbcon_cfb32; display->dispsw_data = current_par.cmap.cfb32; - display->visual = FB_VISUAL_TRUECOLOR; + visual = FB_VISUAL_TRUECOLOR; break; #endif default: display->dispsw = &fbcon_dummy; + visual = FB_VISUAL_MONO10; break; } - info->screen_base = (char *)current_par.screen_base; - display->type = FB_TYPE_PACKED_PIXELS; - display->type_aux = 0; - display->ypanstep = 1; - display->ywrapstep = 1; - display->line_length = display->next_line = (var->xres * var->bits_per_pixel) / 8; - display->can_soft_blank = display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0; + display->can_soft_blank = visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0; display->inverse = 0; if (chgvar && info && info->changevar) @@ -1036,16 +994,18 @@ unsigned long start, size; int control; + info->fix.visual = visual; + #if defined(HAS_MEMC) start = 0; - size = current_par.screen_size - VDMA_XFERSIZE; + size = info->fix.smem_len - VDMA_XFERSIZE; control = 0; memc_write(VDMA_START, start); memc_write(VDMA_END, size >> 2); #elif defined(HAS_IOMD) - start = current_par.screen_base_p; + start = info->fix.smem_start; size = current_par.screen_end; if (current_par.using_vram) { @@ -1060,8 +1020,8 @@ iomd_writel(size, IOMD_VIDEND); iomd_writel(control, IOMD_VIDCR); #endif - acornfb_update_dma(var); - acornfb_set_timing(var); + acornfb_update_dma(info, var); + acornfb_set_timing(info, var); if (display->cmap.len) cmap = &display->cmap; @@ -1090,7 +1050,7 @@ if (y_bottom > fb_display[con].var.yres_virtual) return -EINVAL; - acornfb_update_dma(var); + acornfb_update_dma(info, var); fb_display[con].var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) @@ -1147,8 +1107,8 @@ off = vma->vm_pgoff << PAGE_SHIFT; - start = current_par.screen_base_p; - len = PAGE_ALIGN(start & ~PAGE_MASK) + current_par.screen_size; + start = info->fix.smem_start; + len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len; start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; @@ -1176,23 +1136,21 @@ } static struct fb_ops acornfb_ops = { - .owner = THIS_MODULE, - .fb_get_fix = acornfb_get_fix, - .fb_get_var = acornfb_get_var, - .fb_set_var = acornfb_set_var, - .fb_get_cmap = acornfb_get_cmap, - .fb_set_cmap = gen_set_cmap, - .fb_setcolreg = acornfb_setcolreg, - .fb_pan_display =acornfb_pan_display, - .fb_blank = acornfb_blank, - .fb_mmap = acornfb_mmap, + .owner = THIS_MODULE, + .fb_set_var = acornfb_set_var, + .fb_get_cmap = acornfb_get_cmap, + .fb_set_cmap = gen_set_cmap, + .fb_setcolreg = acornfb_setcolreg, + .fb_pan_display = acornfb_pan_display, + .fb_blank = acornfb_blank, + .fb_mmap = acornfb_mmap, }; static int acornfb_updatevar(int con, struct fb_info *info) { if (con == info->currcon) - acornfb_update_dma(&fb_display[con].var); + acornfb_update_dma(info, &fb_display[con].var); return 0; } @@ -1302,15 +1260,24 @@ strcpy(fb_info.modename, "Acorn"); strcpy(fb_info.fontname, "Acorn8x8"); - fb_info.node = NODEV; - fb_info.fbops = &acornfb_ops; - fb_info.disp = &global_disp; - fb_info.changevar = NULL; - fb_info.switch_con = acornfb_switch; - fb_info.updatevar = acornfb_updatevar; - fb_info.flags = FBINFO_FLAG_DEFAULT; + fb_info.node = NODEV; + fb_info.fbops = &acornfb_ops; + fb_info.disp = &global_disp; + fb_info.changevar = NULL; + fb_info.switch_con = acornfb_switch; + fb_info.updatevar = acornfb_updatevar; + fb_info.flags = FBINFO_FLAG_DEFAULT; + + strcpy(fb_info.fix.id, "Acorn"); + fb_info.fix.type = FB_TYPE_PACKED_PIXELS; + fb_info.fix.type_aux = 0; + fb_info.fix.xpanstep = 0; + fb_info.fix.ypanstep = 1; + fb_info.fix.ywrapstep = 1; + fb_info.fix.line_length = 0; + fb_info.fix.accel = FB_ACCEL_NONE; - global_disp.dispsw = &fbcon_dummy; + global_disp.dispsw = &fbcon_dummy; /* * setup initial parameters @@ -1618,10 +1585,10 @@ } } - fb_info.currcon = -1; - current_par.screen_base = SCREEN_BASE; - current_par.screen_base_p = SCREEN_START; - current_par.using_vram = 0; + fb_info.currcon = -1; + fb_info.screen_base = (char *)SCREEN_BASE; + fb_info.fix.smem_start = SCREEN_START; + current_par.using_vram = 0; /* * If vram_size is set, we are using VRAM in @@ -1653,27 +1620,26 @@ * VRAM. Archimedes/A5000 machines use a * fixed address for their framebuffers. */ - int order = 0; - unsigned long page, top; - while (size > (PAGE_SIZE * (1 << order))) - order++; - current_par.screen_base = __get_free_pages(GFP_KERNEL, order); - if (current_par.screen_base == 0) { + unsigned long page, top, base; + int order = get_order(size); + + base = __get_free_pages(GFP_KERNEL, order); + if (base == 0) { printk(KERN_ERR "acornfb: unable to allocate screen " "memory\n"); return -ENOMEM; } - top = current_par.screen_base + (PAGE_SIZE * (1 << order)); + top = base + (PAGE_SIZE << order); + /* Mark the framebuffer pages as reserved so mmap will work. */ - for (page = current_par.screen_base; - page < PAGE_ALIGN(current_par.screen_base + size); - page += PAGE_SIZE) + for (page = base; page < PAGE_ALIGN(base + size); page += PAGE_SIZE) SetPageReserved(virt_to_page(page)); /* Hand back any excess pages that we allocated. */ - for (page = current_par.screen_base + size; page < top; page += PAGE_SIZE) + for (page = base + size; page < top; page += PAGE_SIZE) free_page(page); - current_par.screen_base_p = - virt_to_phys((void *)current_par.screen_base); + + fb_info.screen_base = (char *)base; + fb_info.fix.smem_start = virt_to_phys(fb_info.screen_base); } #endif #if defined(HAS_VIDC) @@ -1683,7 +1649,7 @@ free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE); #endif - current_par.screen_size = size; + fb_info.fix.smem_len = size; current_par.palette_size = VIDC_PALETTE_SIZE; /* @@ -1734,9 +1700,9 @@ v_sync = h_sync / (init_var.yres + init_var.upper_margin + init_var.lower_margin + init_var.vsync_len); - printk(KERN_INFO "Acornfb: %ldkB %cRAM, %s, using %dx%d, " + printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, " "%d.%03dkHz, %dHz\n", - current_par.screen_size / 1024, + fb_info.fix.smem_len / 1024, current_par.using_vram ? 'V' : 'D', VIDC_NAME, init_var.xres, init_var.yres, h_sync / 1000, h_sync % 1000, v_sync); diff -Nru a/drivers/video/acornfb.h b/drivers/video/acornfb.h --- a/drivers/video/acornfb.h Tue Oct 15 20:29:17 2002 +++ b/drivers/video/acornfb.h Tue Oct 15 20:29:17 2002 @@ -47,10 +47,7 @@ }; struct acornfb_par { - unsigned long screen_base; - unsigned long screen_base_p; unsigned long screen_end; - unsigned long screen_size; unsigned int dram_size; unsigned int vram_half_sam; unsigned int palette_size; diff -Nru a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c --- a/drivers/video/clps711xfb.c Tue Oct 15 20:29:12 2002 +++ b/drivers/video/clps711xfb.c Tue Oct 15 20:29:12 2002 @@ -25,6 +25,7 @@ #include #include #include +#include #include